2014-12-21 3 views
8

Es wäre nützlich, "conexpr" -Parameter zu haben, um Compiler-bekannte Werte zu unterscheiden und so in der Kompilierzeit Fehler erkennen zu können. Beispiele:Warum 'constexpr' Parameter nicht erlaubt sind?

int do_something(constexpr int x) 
{ 
    static_assert(x > 0, "x must be > 0"); 
    return x + 5; 
} 

int do_something(int x) 
{ 
    if(x > 0) { cout << "x must be > 0" << endl; exit(-1); } 
    return x + 5; 
} 

int var; 

do_something(9); //instance 'do_something(constexpr int x)' and check arg validity at compile-time 

do_something(0); //produces compiler-error 

do_something(var); //instance 'do_something(int x)' 

Was ist ein ungültiger Code für jetzt. Kann mir jemand erklären, warum das nicht umgesetzt werden kann?

EDIT:

Vorlagen Benutzer verwenden sollte sicherstellen, dass Literale wird immer als Vorlage Argument und nicht als Funktion diejenigen geführt, die sehr unbequem:

template<int x> 
int do_something() 
{ 
    static_assert(x > 0, "x must be > 0"); 
    return x + 5; 
} 

int do_something(int x) 
{ 
    if(x > 0) { cout << "x must be > 0" << endl; exit(-1); } 
    return x + 5; 
} 

int var; 

do_something(9); //instance 'do_something(int x)' and doesn't checks validity at compile-time 

do_something(0); //same as above, if check was performed - compiler error should occur 

do_something<9>(); //instance template 'do_something<int>()' 

do_something<0>(); //produces compiler error 

do_something(var); //instance 'do_something(int x)' 
+1

Können Sie das nicht schon mit einer Vorlage tun? Genauer gesagt mit nicht typisierten Vorlagenparametern? – Borgleader

+0

Dann sollte der Benutzer meiner Funktion eine andere Syntax für den Aufruf angeben, abhängig davon, ob der Parameter zur Kompilierzeit bekannt ist. – AnArrayOfFunctions

+0

ein assert() könnte vermutlich für den Fall optimiert werden, dass ein consExpr-Wert übergeben wurde. –

Antwort

-4

Während dies in der Theorie gut klingt, ist es nicht nützlich in der realen Welt. Die meisten Argumente für Funktionen sind keine Kompilierzeitkonstanten, und viele Bedingungen sind auch zur Kompilierzeit nicht genau bekannt.

Eine solche Überladung zu spezifizieren und zu implementieren wäre eine erhebliche Menge an Arbeit, und sie würde nicht so viel verwendet werden. Wenn Sie über Begrenzungen und Argumente für die Kompilierungszeit verfügen, können Sie normalerweise die gesamte Funktion zum Zeitpunkt der Kompilierung auswerten, was bedeutet, dass eine Überladung nicht erforderlich ist.

+1

Dies beantwortet nicht speziell WARUM, was die Frage stellt. – cybermonkey

+0

@cybermonkey Ich stimme natürlich nicht zu. Ich habe versucht zu erklären, warum das Feature nicht im Standard ist, indem ich beschrieben habe, warum es nicht sinnvoll genug ist, um den Aufwand zu rechtfertigen.Im Gegensatz zu der anderen Antwort auf diese Frage, die das Warum in keiner Weise, Form oder Form beantwortet, sondern nur versucht, eine Problemumgehung zu beschreiben (d. H. Tatsächlichen Code, der gerade zeigt, was ich in meinem zweiten Absatz schreibe). –

2

Wenn ich verstehe, was Sie versuchen, richtig zu machen, ist die Funktionalität, die Sie anfordern, bereits verfügbar. Es ist nicht das eleganteste, aber ich denke, das ist gut genug.

Sie möchten eine Funktion zur Kompilierzeit und Laufzeit mit der gleichen Syntax aufrufen und wenn möglich zur Kompilierzeit auswerten, andernfalls sollte sie zur Laufzeit ausgewertet werden. Sie müssen Assertions für die Funktion unabhängig davon, wann sie aufgerufen wird, ausgewertet werden.

Ich glaube, dies wird tun, was Sie wollen:

constexpr int do_something(int x) 
{ 
    if(x <= 0) 
    { 
     std::cout << "x must be > 0" << std::endl; exit(-1); 
    } 
    return x + 5; 
} 

constexpr int compiletime_good = do_something(5); 
constexpr int compiletime_bad = do_something(0); // Fails at compile-time 

int runtime_good = do_something(5); 
int runtime_bad = do_something(0); // Fails at runtime 

constexpr int val_good = 5; 
constexpr int val_bad = 0; 

do_something(val_good); 
do_something(val_bad); // Fails at run-time 

int valrun_good = 5; 
int valrun_bad = 0; 

do_something(valrun_good); 
do_something(valrun_bad); // Fails at run-time 

Der Trick hier ist bei der Kompilierung in einer Art und Weise zu versagen, die nicht static_assert erfordert, und wird auch zur Laufzeit fehlschlagen.

+1

Was bedeutet, dass jede Instanz von 'do_something' aufgerufen werden muss, wo 'constexpr' erwartet wird, was nicht besser ist als die Verwendung von Templates. – AnArrayOfFunctions

+0

@ FISOCPP Fair genug. Ich nehme an, der Grund, warum wir keine explizite Möglichkeit haben, consExpr-Parameter in die Art und Weise einzubeziehen, wie Sie es wünschen, ist, dass niemand sich die Mühe gemacht hat, aufzuschreiben und einen Vorschlag durchzusetzen. Ich würde es gerne sehen, aber es klingt nach viel Arbeit. –

+1

Man sollte natürlich eine vorhandene Einrichtung verwenden, um einen Assertionsfehler zu melden, und nicht 'std :: exit()' Aufrufe in der Codebase streuen. Ansonsten ist das sehr gut. –