C ++ 17 führt Inline-Variablen ein
C ++ 17 behebt dieses Problem für constexpr static
Mitgliedsvariablen, die eine Out-of-Line-Definition erfordern, wenn sie odr-verwendet wurden. In der zweiten Hälfte dieser Antwort finden Sie Details vor C ++ 17.
Vorschlag P0386 Inline-Variablen bietet die Möglichkeit, den inline
Spezifizierer auf Variablen anzuwenden . Insbesondere in diesem Fall constexpr
impliziert inline
für statische Elementvariablen. Der Vorschlag lautet:
Der Inline-Bezeichner kann sowohl auf Variablen als auch auf Funktionen angewendet werden. Eine inline deklarierte Variable hat dieselbe Semantik wie eine inline deklarierte Funktion: Sie kann identisch in mehreren Übersetzungseinheiten definiert werden, muss in jeder Übersetzungseinheit definiert werden, in der sie odr verwendet wird, und das Verhalten des Programms ist wie folgt Es gibt genau eine Variable.
und modifiziert [basic.def] p2:
Eine Erklärung ist eine Definition, es sei denn
...
- Es deklariert ein statisches Datenelement außerhalb einer Klassendefinition und die Variable wurde innerhalb der Klasse mit dem constexpr-Spezifizierer definiert (diese Verwendung ist veraltet; siehe [depl.static_constexpr]).
...
und füge [depl.static_constexpr] hinzu :
Aus Gründen der Kompatibilität mit früheren internationalen C ++ - Standards kann ein statisches Datenelement von constexpr ohne Initialisierer außerhalb der Klasse redundant deklariert werden. Diese Verwendung ist veraltet. [Beispiel:
struct A {
static constexpr int n = 5; // definition (declaration in C++ 2014)
};
constexpr int A::n; // redundant declaration (definition in C++ 2014)
- Beispiel beenden]
C ++ 14 und früher
In C ++ 03 durften wir nur klasseninterne Initialisierer für const-Integrale oder const-Aufzählungstypen bereitstellen. In C ++ 11 wurde constexpr
diese Verwendung auf Literal-Typen erweitert .
In C ++ 11 müssen wir keine Namespace-Bereichsdefinition für ein statisches constexpr
Mitglied angeben , wenn es nicht von odr verwendet wird. Dies können Sie dem Entwurf des C ++ 11-Standardabschnitts 9.4.2
[class.static.data] entnehmen, in dem es heißt ( Hervorhebung meiner in Zukunft ):
[...] Ein statisches Datenelement vom Typ Literal kann in der Klassendefinition mit dem Bezeichner constexpr deklariert werden. In diesem Fall muss in der Deklaration ein Klammer-oder-Gleich-Initialisierer angegeben werden, in dem jede Initialisierer-Klausel, die ein Zuweisungsausdruck ist, ein konstanter Ausdruck ist. [Hinweis: In beiden Fällen kann das Mitglied in konstanten Ausdrücken erscheinen. —End note]
Das Mitglied muss weiterhin in einem Namespace-Bereich definiert werden, wenn es im Programm odr-verwendet wird (3.2) und die Definition des Namespace-Bereichs keinen Initialisierer enthält.
Dann stellt sich die Frage, baz
ob hier etwas verwendet wird :
std::string str(baz);
Die Antwort lautet " Ja" . Daher benötigen wir auch eine Definition des Namespace-Bereichs.
Wie bestimmen wir also, ob eine Variable odr-verwendet wird ? Der ursprüngliche C ++ 11-Wortlaut in Abschnitt 3.2
[basic.def.odr] lautet:
Ein Ausdruck wird möglicherweise ausgewertet, es sei denn, es handelt sich um einen nicht bewerteten Operanden (Abschnitt 5) oder einen Unterausdruck davon. Eine Variable, deren Name als potenziell ausgewerteter Ausdruck angezeigt wird, wird odr verwendet, es sei denn,
es handelt sich um ein Objekt, das die Anforderungen für das Erscheinen in einem konstanten Ausdruck (5.19) erfüllt, und die Konvertierung von Wert zu Wert (4.1) wird sofort angewendet .
So baz
hat sich eine Ausbeute konstanten Ausdruck aber die L - Wert-zu-R - Wert - Umwandlung nicht sofort angewendet , da es nicht anwendbar ist auf Grund baz
ist ein Array. Dies wird in Abschnitt 4.1
[conv.lval] behandelt, der besagt:
Ein gl-Wert (3.10) eines nicht funktionierenden Nicht-Array-Typs T kann in einen pr-Wert konvertiert werden.53 [...]
Was in der angelegten Array-zu-Zeiger Umwandlung .
Dieser Wortlaut von [basic.def.odr] wurde aufgrund des Fehlerberichts 712 geändert, da einige Fälle nicht von diesem Wortlaut abgedeckt wurden, diese Änderungen jedoch die Ergebnisse für diesen Fall nicht ändern.