Warum constexpr anstatt erweiterte call Syntax?
-
Hallo,
ich habe mich in letzter Zeit in
constexpr
eingearbeitet, was schon ein ziemlich nützliches Feature ist. Allerdings verstehe ich nicht so ganz warum das Konzept hinterconstexpr
(also Code zur Compile-Zeit auszuwerten) so implementiert ist, wie es ist.Das man eine Variable wie z.B.
constexpr int i = 0;
mitconstexpr
deklarieren muss, macht ja Sinn. Aber warum auch Funktionen?Meiner (aktuellen) Meinung nach führt das zu folgenden Nachteilen:
- Inflationäre Benutzung des
constexpr
keywords (weil zu mindest in meinem Code ca. 80% aller Funktionen alsconstexpr
deklariert werden können). - Weniger "Macht" beim User: Ob eine constexpr Funktion tatsächlich zur Compile-Zeit ausgewertet wird kann man nur über Umwege wie die Deklaration einer lokalen
constexpr
Variable erzwingen. Andererseits kann es sein dass ich eine Funktion trotzconstexpr
zur Laufzeit aufrufen will, der Compiler aber anderer Meinung ist.
Warum nicht einfach in der Art (Syntax ist natürlich provisorisch):
void foo() {} int bar() { return 1; } int main() { foo(); // (1) Standard: Compiler entscheidet foo!rt(); // (2) Erweiterte call Syntax: foo wird (garantiert) zur Runtime ausgewertet foo!ct(); // (3) foo wird (garantiert) zur Compiletime ausgewertet foo!at(); // (4) Wie (1) nur explizit, Compiler entscheidet automatisch int i1 = bar(); // Standard int i2 = bar!ct(); // Äquivalent zu: int i2 = 1; constexpr int i3 = bar(); // Compiler nimmt automatisch !ct wegen constexpr constexpr int i4 = bar!rt(); // Compile-Fehler }
Dann könnte man als Benutzer immer das verwenden was man gerade braucht, hätte also vollständige Kontrolle. Außerdem müsste man gar keine Funktion mehr als
constexpr
deklarieren, da man dies einfach über den Aufruf steuern könnte.Würde etwas gegen eine solche Lösung sprechen?
- Inflationäre Benutzung des
-
Du musst überhaupt nichts
constexpr
machen. Du kannst etwas constexpr machen, wenn du möchtest und der Compiler kann dann kontrollieren, ob das auch wirklich stimmt, was du da behauptest. Und den Aufrufer interessieren solche Implementierungsdetails einen Dreck. Der freut sich entweder, dass der Code schön flott ist oder ärgert sich, wenn er es nicht ist.Du scheinst die Idee hinter
constexpr
in jedweder Hinsicht falsch verstanden zu haben.
-
SeppJ schrieb:
Du musst überhaupt nichts
constexpr
machen. Du kannst etwas constexpr machen, wenn du möchtest und der Compiler kann dann kontrollieren, ob das auch wirklich stimmt, was du da behauptest.Das ist mir schon klar. Allerdings macht es doch keinen Sinn eine Funktion nicht
constexpr
zu machen, wenn es prinzipiell möglich ist und auch sonst nichts dagegen spricht. Sagen wir ich habe etwas wiechar to_lower(char c) { // Implementierung }
und ich brauche das in meiner Anwendung sowieso nur für Strings die zur Laufzeit entstehen. Dann kann ich die Funktion einfach nehmen. Aber vielleicht brauche ich die Funktion ja doch irgendwann mal zur Compilezeit, wer weiß das schon.
Deswegen würde ich die Funktion jetzt einfach auch schonmal vorsorglich
constexpr
deklarieren: Schlicht aus dem Grund weil nichts dagegen spricht.SeppJ schrieb:
Und den Aufrufer interessieren solche Implementierungsdetails einen Dreck. Der freut sich entweder, dass der Code schön flott ist oder ärgert sich, wenn er es nicht ist.
Du scheinst die Idee hinter
constexpr
in jedweder Hinsicht falsch verstanden zu haben.Das wäre ja nach wie vor gegeben.
Wenn es dem Anwender "egal" ist was passiert, schreibt er einfach
foo();
wie jetzt auch schon. Dann entscheidet der Compiler und der Aufrufer kann sich freuen oder eben nicht.Worum es mir geht ist aber genau der umgekehrte Fall, wenn es dem Aufrufer nicht egal ist.
Das ist keine Einschränkung da etwas wie
constexpr int i = f();
immer noch genauso funktionieren würde wie jetzt auch (habe ein paar weitere Beispiele zu dem Anfangspost hinzugefügt).
-
Du darfst constexpr Funktionen auch zur Laufzeit mit variablen Argumenten aufrufen!
-
SeppJ schrieb:
Du darfst constexpr Funktionen auch zur Laufzeit mit variablen Argumenten aufrufen!
Das weiß ich. Deswegen habe ich ja auch geschrieben:
happystudent schrieb:
und ich brauche das in meiner Anwendung sowieso nur für Strings die zur Laufzeit entstehen.
...
Deswegen würde ich die Funktion jetzt einfach auch schonmal vorsorglichconstexpr
deklarieren: Schlicht aus dem Grund weil nichts dagegen spricht.Könnte ich eine
constexpr
Funktion nicht auch zur Laufzeit mit variablen Argumenten aufrufen, käme sie wohl kaum für meine Anwendung in Frage (in der, wie beschrieben, ausschließlich mit Strings, welche zur Laufzeit erzeugt werden, gearbeitet wird).Das ist aber nicht der Punkt.
Mir geht es u.a. darum dass man als User nicht direkt steuern kann ob eine Funktion jetzt zur Lauf- oder Compilezeit ausgewertet werden soll. Dafür braucht man dann z.B. entweder eine lokale
constexpr
Variable oder solche "Tricks" wiestd::integral_constant
(was aber auch nicht immer geht, z.B. bei doubles).Oder andersrum, ich habe eine
constexpr
Funktion die zur Laufzeit ausgewertet werden soll, aber der Compiler entscheidet sich dafür diese zur Compilezeit auszuwerten.
-
-
[OT]
Gibt's eigentlich schon eine Möglichkeit unterschiedliche Implementierungen für compiletime und runtime Ausführung zu machen? Quasi constexpr Overloads. Also z.B. für Fälle wo man durch die constexpr Einschränkungen nur eine langsamere Version implementieren kann.
[/OT]
-
happystudent schrieb:
Dafür braucht man dann z.B. entweder eine lokale
constexpr
VariableEben. Problem gelöst. So oft braucht man das nicht, d.h. diese zusätzliche Zeile ist durchaus akzeptabel.
happystudent schrieb:
Oder andersrum, ich habe eine
constexpr
Funktion die zur Laufzeit ausgewertet werden soll, aber der Compiler entscheidet sich dafür diese zur Compilezeit auszuwerten.Wofür sollte das gut sein? Also die Ausführung zur Laufzeit zu erzwingen. Davon abgesehen... es gibt ohne compilerspezifische Erweiterungen und "Tricks" sowieso nichtmal ne Möglichkeit das für normale Funktionen zu garantieren. Der Compiler darf immer inlinen und dann Dinge zur Compilezeit berechnen wenn er es hinbekommt.
-
Gast3 schrieb:
http://stackoverflow.com/questions/14472359/why-do-we-need-to-mark-functions-as-constexpr
Also man braucht es hauptsächlich um Compile-Zeiten und evtl. nicht benötigte Instanziierung zu reduzieren? Ist das nicht eher etwas was mir als Aufrufer relativ egal sein sollte? Dann könnte man das keyword doch auch einfach otional machen?
Oder beziehst du dich auf die erste Antwort (die mit den meisten Upvotes)? Die überzeugt mich ehrlich gesagt nicht, weil seine Kernaussage ist ja dass
constexpr
quasi Teil des Interfaces ist. Also verhindern soll dass eine Änderung der Implementierung vonf
das Interface vonf
ändert.Genau das kann man aber ja eben nicht erreichen, weil auch wenn ich
f
alsconstexpr
markiere kann ich durch eine Änderung der Implementierung dafür sorgen dass bestimmte Argumente vonf
nicht mehrconstexpr
Auswertbar sind. Womit ich wiederum bestehenden Code brechen kann ohne etwas am Interface vonf
geändert zu haben.Schlimmer sogar, als Anwender kann man solche Interface Änderungen gar nicht erkennen.
hustbaer schrieb:
Eben. Problem gelöst. So oft braucht man das nicht, d.h. diese zusätzliche Zeile ist durchaus akzeptabel.
Kann man natürlich so sehen. Ich frage mich aber halt eher warum man nicht einfach dem Benutzer volle Flexibilität gibt.
hustbaer schrieb:
Wofür sollte das gut sein? Also die Ausführung zur Laufzeit zu erzwingen. Davon abgesehen... es gibt ohne compilerspezifische Erweiterungen und "Tricks" sowieso nichtmal ne Möglichkeit das für normale Funktionen zu garantieren. Der Compiler darf immer inlinen und dann Dinge zur Compilezeit berechnen wenn er es hinbekommt.
Zum debuggen z.B. fände ich das sehr praktisch.
Oder ein konkretes Beispiel hier. Hier will man ja das das Encoding zur Compilezeit passiert und das Decoding nur zur Laufzeit.
Konsistent wäre, sowohl die
encode
als auch diedecode
Funktion alsconstexpr
zu markieren, da ja prinzipiell beide mit Compiletime Strings arbeiten können (dieencode
Funktion das ja sogar soll).Geht aber nicht. Für die
decode
Funktion muss ich eine eigene Runtime-Variante anlegen, da der Compiler die Dekodierung immer zur Compilezeit durchführt. Hier würde ich ihm gerne einfach sagen können: bitte an dieser Stelle die Funktion garantiert zur Laufzeit auswerten.Letztendlich führt das dann halt dazu dass man solche Funktionen doppelt implementieren muss (zumindest habe ich noch keine bessere Alternative gefunden).
-
happystudent schrieb:
Zum debuggen z.B. fände ich das sehr praktisch.
OK. Das ist der einzige Punkt den ich halbwegs nachvollziehen kann.
Darf aber natürlich jede Implementierung gerne irgendwelche Erweiterungen anbieten die das möglich machen. Bzw. kann man die Funktion zum Testen/Durchsteppen auch einfach so aufrufen dass der Compiler nicht "sehen" kann (darf) dass der Wert cc-konstant ist. Bei Integers z.B. einfach indem man sie in ne volatile Variable schreibe und wieder daraus zurückliest.
happystudent schrieb:
Oder ein konkretes Beispiel hier. Hier will man ja das das Encoding zur Compilezeit passiert und das Decoding nur zur Laufzeit.
(...)
Das ist super spezieller Spezialfall. Dafür willst du den Standard aufbohren? Ne...