Forum: Compiler & IDEs C++ constexpr does NOT imply inline


von Vincent H. (vinci)


Lesenswert?

Grüß euch

Ich war bis gestern Abend der Meinung dass constexpr gleichzeitig 
überall auch inline impliziert. Wie ich dann allerdings herausfand ist 
dies schlichtweg falsch...

Nun, normalerweise poste ich nicht ständig wenn ich mich irgendwo irr, 
man will ja nicht das Forum zuspamen ;) , aber in diesem Fall klafft 
imho ein recht großes Wissens-Loch in der C++ Community. Ich hab beim 
Googlen unzählige Blog-Einträge gefunden die einfach 3 Zeilen aus dem 
Standard rauskopieren und "constepxr implies inline" schreiben.

Tatsächlich gilt das aber ausschließlich für Funktionen und static 
member variables (siehe etwa cppreference):
"A constexpr specifier used in a function or static member variable 
(since C++17) declaration implies inline."
https://en.cppreference.com/w/cpp/language/constexpr

Oder viel deutlicher in P0386R2:
"The constexpr specifier implies inline only for static data members, 
not also for namespace-scope variables."
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0386r2.pdf

Für normale Variablen gilt das also schlichtweg nicht. Das allein wär 
meiner Ansicht nach noch nicht so schlimm. Was die Sache aber ungut 
macht ist, dass für constexpr eine Art ODR-Ausnahme existiert die 
mehrere Definitionen explizit erlaubt... Das heißt im Klartext, dass der 
Compiler (ohne LTO) für jede constexpr Variable in einem Header pro 
translation unit eine Kopie anlegt.

Da muss man dem Standard Komitee wirklich gratulieren, man hat hier 
erfolgreich den worst-case beschloßen. -.-

von mh (Gast)


Lesenswert?

Vincent H. schrieb:
> Da muss man dem Standard Komitee wirklich gratulieren, man hat hier
> erfolgreich den worst-case beschloßen. -.-

Ich hab mich selbst noch nicht wirklich mit dem Thema beschäftigt, 
deswegen kann ich nicht wirlich beurteilen, wie sinnvoll/unsinngig der 
Standard an dieser Stelle ist.

Ich kann verstehen, dass man bei so einer Erkenntnis andere informieren 
und warnen möchte. Ich verstehe allerdings nicht, warum du deinen Post 
mit so einem "vernichtenden" Urteil beendest. Warum gehst du davon aus, 
dass es der worst-case ist? Gibt es eine bessere Möglichkeit mit der 
"alle" zufrieden sind? Wenn du eine bessere Möglichkeit kennst, wäre es 
nett sie zusammen mit deinem "vernichtenden" Urteil zu veröffentlichen.

Ich persönlich gehe erstmal davon aus, dass das Komitee einen guten 
Grund für den aktuellen Stand hat.

von Vincent H. (vinci)


Lesenswert?

Der worst-case ist es, weil die aktuelle Regelung die blödeste Variante 
einer 2er Kombination ist... Es gibt ein implizites inline für 2/3 
Fällen und dank der ODR Ausnahme gibts weder Warnung noch Fehler für den 
Fall der durchfällt.

Für einen überwältigenden Anteil an C++ Nutzern spielt dieses Detail 
sicher überhaupt keine Rolle. Aber grad wenn jedes kB an Speicher weh 
tut, dann fällts natürlich ins Gewicht.

Lustiges Detail am Rande. Ich wär selbst grad nicht drübergestolpert, 
würde LTO in meiner aktuellen Compiler Version nicht irgendwie die Debug 
Info zerschießen...

von M.K. B. (mkbit)


Lesenswert?

Vincent H. schrieb:
> Für normale Variablen gilt das also schlichtweg nicht. Das allein wär
> meiner Ansicht nach noch nicht so schlimm. Was die Sache aber ungut
> macht ist, dass für constexpr eine Art ODR-Ausnahme existiert die
> mehrere Definitionen explizit erlaubt... Das heißt im Klartext, dass der
> Compiler (ohne LTO) für jede constexpr Variable in einem Header pro
> translation unit eine Kopie anlegt.

Was bleibt dem Compiler auch anderes übrig. Jede Unit wird einzeln 
übersetzt und braucht die entsprechende Variable, damit lässt sich auch 
der Buildprozess gut parallelisieren. Der Linker kann dann dafür sorgen, 
dass am Ende nur eine davon ins binary kommt.

Ich hab den Standard jetzt nicht gelesen, aber nach deinem Zitat 
verbietet es der Standard auch nicht, dass der Compiler nur eine Instanz 
anlegt, er muss es halt nicht.

Ansonsten kannst du ja auch explizit inline dazuschreiben, wenn es dir 
wichtig ist (korrigiere mich bitte, wenn meine Annahme hier falsch ist).

Ich persönlich verwende inline nie zur Optimierung (nur für multiple 
definition) und überlasse die Optimierung dem Compiler. Da kann ich dann 
auch je nach Target entscheiden, ob dieser auf Codegröße oder 
Geschwindigkeit optimieren soll. Außerdem ist inline sowieso nicht 
binden
"Since this meaning of the keyword inline is non-binding, compilers are 
free to use inline substitution for any function that's not marked 
inline, and are free to generate function calls to any function marked 
inline."
https://en.cppreference.com/w/cpp/language/inline

von Vincent H. (vinci)


Lesenswert?

Inline für Variablen hat mit Optimierungen überhaupt nichts zu tun und 
ist sehr wohl bindend.

Und ja, natürlich kann ich explizit inline dazu schreiben. Wenn ich 
garantiert keine Kopie haben will dann muss ich das sogar. Der 
springende Punkt ist, dass ich mir darüber nicht im Klaren war... und 
ich glaub da bin ich nicht der einzige.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.