Bedeutet constexpr Inline?

105

Betrachten Sie die folgende Inline-Funktion:

// Inline specifier version
#include<iostream>
#include<cstdlib>

inline int f(const int x);

inline int f(const int x)
{
    return 2*x;
}

int main(int argc, char* argv[])
{
    return f(std::atoi(argv[1]));
}

und die constexpr äquivalente Version:

// Constexpr specifier version
#include<iostream>
#include<cstdlib>

constexpr int f(const int x);

constexpr int f(const int x)
{
    return 2*x;
}

int main(int argc, char* argv[])
{
    return f(std::atoi(argv[1]));
}

Meine Frage ist: constexprBedeutet der Bezeichner den Bezeichner inlinein dem Sinne, dass constexprder Compiler , wenn ein nicht konstantes Argument an eine Funktion übergeben wird, versucht, inlinedie Funktion so auszuführen, als ob der Bezeichner inlinein seine Deklaration aufgenommen worden wäre?

Garantiert der C ++ 11-Standard dies?

Vincent
quelle
5
'[Wird] der Compiler versuchen, die Funktion zu integrieren?' Ist nicht das, was der inlineSpezifizierer tut. (Oder vielleicht habe ich Ihre Formulierung falsch verstanden.)
Luc Danton
5
Der inlineSpezifizierer hat nichts mehr mit Inlining
K-Ballo
2
Die Frage basiert auf der falschen Annahme, die inlinein direktem Zusammenhang mit Inlining steht. Also nein, der constexprSpezifizierer impliziert den inlineSpezifizierer nicht in diesem Sinne, da dieser Sinn nicht existiert.
Christian Rau

Antworten:

139

Ja ([dcl.constexpr], §7.1.5 / 2 im C ++ 11-Standard): "constexpr-Funktionen und constexpr-Konstruktoren sind implizit inline (7.1.2)."

Beachten Sie jedoch, dass der inlineBezeichner nur sehr geringe (wenn überhaupt) Auswirkungen darauf hat, ob ein Compiler eine Funktion wahrscheinlich inline erweitert oder nicht. Dies wirkt sich jedoch auf die eine Definitionsregel aus, und aus dieser Perspektive muss der Compiler dieselben Regeln für eine constexprFunktion als inlineFunktion befolgen .

Ich sollte auch hinzufügen, dass die Regeln für Funktionen in C ++ 11 unabhängig davon constexprimplizierten inline, constexprdass sie so einfach waren, dass sie oft gute Kandidaten für eine Inline-Erweiterung waren (die Hauptausnahme sind diejenigen, die rekursiv sind). Seitdem sind die Regeln jedoch zunehmend lockerer geworden und constexprkönnen daher auf wesentlich größere, komplexere Funktionen angewendet werden.

Jerry Sarg
quelle
Angesichts der Idee, dass konstante Ausdrücke zur Kompilierungszeit ausgewertet werden, werden die meisten Verwendungen von constexprFunktionen vermutlich überhaupt keine Codegenerierung verursachen ...
Kerrek SB
11
@ KerrekSB- constexprFunktionen werden möglicherweise zur Kompilierungszeit ausgewertet. Der C ++ 14-Standard ist jedoch mit solchen übersät, die sehr wahrscheinlich zur Laufzeit aufgerufen werden. Zum Beispiel:std::array<T,N>::at
Namensgeber
@Eponymous ja, aber nur die am meisten reduzierte Form bleibt als Opcodes. Beispiel: Die gebundenen Prüfungen werden zur Erstellungszeit ausgewertet, da ihr Codepfad const ist. Der zurückgegebene Wert ist jedoch * (Daten + Offset)
v.oddou
16

constexprbedeutet nicht inlinefür nicht statische Variablen (C ++ 17 Inline-Variablen)

Während constexprbedeutet inlinefür Funktionen, hat es nicht , dass die Wirkung für nicht-statische Variablen, C ++ unter Berücksichtigung 17 Inline - Variablen.

Wenn Sie zum Beispiel das minimale Beispiel nehmen, das ich unter gepostet habe: Wie funktionieren Inline-Variablen? und entfernen Sie das inline, lassen Sie nur constexpr, dann erhält die Variable mehrere Adressen, was die Hauptsache ist, die Inline-Variablen vermeiden.

constexpr statische Variablen sind jedoch implizit statisch.

Minimal Beispiel , das constexprbedeutet inlinefür Funktionen

Wie unter https://stackoverflow.com/a/14391320/895245 erwähnt, besteht der Haupteffekt inlinedarin, nicht zu inline, sondern mehrere Definitionen einer Funktion zuzulassen. Standardzitat unter: Wie kann eine C ++ - Headerdatei die Implementierung enthalten?

Wir können das beobachten, indem wir mit dem folgenden Beispiel spielen:

main.cpp

#include <cassert>

#include "notmain.hpp"

int main() {
    assert(shared_func() == notmain_func());
}

notmain.hpp

#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP

inline int shared_func() { return 42; }
int notmain_func();

#endif

notmain.cpp

#include "notmain.hpp"

int notmain_func() {
    return shared_func();
}

Kompilieren und ausführen:

g++ -c -ggdb3  -O0 -Wall -Wextra -std=c++11 -pedantic-errors  -o 'notmain.o' 'notmain.cpp' 
g++ -c -ggdb3  -O0 -Wall -Wextra -std=c++11 -pedantic-errors  -o 'main.o' 'main.cpp' 
g++ -ggdb3  -O0 -Wall -Wextra -std=c++11 -pedantic-errors  -o 'main.out' notmain.o main.o
./main.out

Wenn wir entfernen inlineaus shared_func, würde Link nicht mit:

multiple definition of `shared_func()'

weil der Header in mehrere .cppDateien aufgenommen wird.

Aber wenn wir ersetzen inlinemit constexpr, dann funktioniert es wieder, denn constexprauch impliziert inline.

GCC implementiert dies, indem die Symbole in den ELF-Objektdateien als schwach markiert werden: Wie kann eine C ++ - Headerdatei die Implementierung enthalten?

Getestet in GCC 8.3.0.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
3
Übrigens ist eine deklarierte statische Klassenmitgliedsvariable constexprimmer noch inline. cppreference.com : Eine constexpr
anton_rh
@anton_rh danke, ich hatte diese Regel nicht gesehen, Antwort aktualisieren.
Ciro Santilli 3 冠状 病 六四 事件 3
Es ist nicht das, was open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0386r0.pdf sagt. es heißt, constexpr impliziert Inline für Variablen. ohne Erwähnung eines Unterschieds zwischen dem Namespace-Bereich und dem Klassenbereich.
v.oddou