Undefined reference to static constexpr char[]
Ich will eine static const
char
array in meiner Klasse. GCC beschwert und sagte mir, ich sollte verwenden constexpr
, obwohl jetzt ist es mir zu sagen, es ist eine Undefinierte Referenz. Wenn ich den array nicht-Mitglied dann kompiliert. Was ist Los?
//.hpp
struct foo {
void bar();
static constexpr char baz[] = "quz";
};
//.cpp
void foo::bar() {
std::string str(baz); //undefined reference to baz
}
Nur eine Ahnung, funktioniert es, wenn baz int zum Beispiel? Können Sie dann darauf zugreifen? Es könnte auch ein bug.
Frage: Die übersetzungseinheit wird es definiert werden? Antwort: Alles, was den Kopf. Problem: Gegen die " one definition rule. Ausnahme: Compile-time-Konstante Integrale können "initialisiert" im Kopf.
Kompiliert er fein wie ein
Angesichts der views und upvotes, diese Frage Bedarf einer ausführlicheren Antwort, die ich unten Hinzugefügt.
Frage: Die übersetzungseinheit wird es definiert werden? Antwort: Alles, was den Kopf. Problem: Gegen die " one definition rule. Ausnahme: Compile-time-Konstante Integrale können "initialisiert" im Kopf.
Kompiliert er fein wie ein
int
@MooingDuck Es funktioniert gut als nicht-Mitglied. Wäre das nicht gegen die Regel verstoßen zu werden?int
s cheat. Als nicht-Mitglied, das sollte nicht erlaubt werden, es sei denn, die Regeln geändert für C++11 (möglich)Angesichts der views und upvotes, diese Frage Bedarf einer ausführlicheren Antwort, die ich unten Hinzugefügt.
InformationsquelleAutor Pubby | 2011-11-04
Du musst angemeldet sein, um einen Kommentar abzugeben.
Hinzufügen, um Ihre cpp-Datei:
Grund: Sie haben, um den definition der statischen Mitglied sowie die Erklärung. Die Deklaration und die Initialisierung gehen Sie in der Klassendefinition, sondern der betreffende definition werden separaten.
Es sieht noch komisch, wenn du deine Klasse Erklärung .cpp-Datei! Initialisieren Sie das Feld in der Klasse Erklärung, aber Sie müssen noch "declare" das Feld schreiben constexpr char foo::baz[] unter der Klasse. Es scheint, dass Entwickler, die mit constexpr können, kompilieren Sie Ihre Programme, indem Sie die folgenden eine seltsame Tipp: erklären Sie es erneut.
Das Wort, das Sie suchen, ist "definieren".
Diese Diskussion ist immer sehr verwirrt.
constexpr
ist noch eine andere, nicht verwandten Sache, nicht unmittelbar verbunden sind mit Gestänge.was wird der Ausdruck Aussehen, wenn foo ist templatized? danke.
InformationsquelleAutor Kerrek SB
C++17 stellt inline-Variablen
C++17 behebt dieses problem für constexpr statische member-Variablen, die eine out-of-line-definition, wenn es ord-verwendet. Siehe die original-Antwort unten für pre C++17 details.
Vorschlag P0386 Inline-Variablen stellt die Fähigkeit zur Anwendung der inline-Spezifizierer Variablen. Insbesondere diesem Fall constexpr impliziert inline für statische member-Variablen. Der Vorschlag sagt:
modifiziert und [basic.def]p2:
hinzufügen und [depr.static_constexpr]:
Ursprüngliche Antwort
In C++03 wir waren nur erlaubt, um in der Klasse intializers für const Integrale oder const Aufzählungstypen, in C++11 mit constexpr diese wurde verlängert, um literal-Typen.
In C++11, die wir nicht brauchen, um eine namespace-scope-definition für ein static constexpr Mitglied, wenn es nicht odr-used, können wir sehen, aus dem draft standard C++11 Abschnitt
9.4.2
[Klasse.statisch.Daten], die sagt (Hervorhebung von mir geht nach vorn):Also stellt sich die Frage, ist
baz
odr-used hier:und die Antwort ist ja, und so benötigen wir einen namespace-scope-definition als auch.
So, wie wir bestimmen, ob eine variable ist odr-used? Die ursprüngliche C++11 Wortlaut der in Abschnitt
3.2
[basic.def.odr] sagt:So
baz
hat, liefern Sie ein konstanter Ausdruck aber die lvalue-rvalue Konvertierung nicht sofort angewendet, da es nicht anwendbar aufgrundbaz
als ein array. Mehr dazu im Abschnitt4.1
[conv.lval], die sagt :Was in den array-to-pointer-conversion.
Diese Formulierung von [basic.def.odr] wurde geändert durch Mängelbericht 712 da einige Fälle nicht abgedeckt wurden, durch diese Formulierung, aber diese änderungen ändern nicht die Ergebnisse für diesen Fall.
constexpr
hat absolut nichts mit der Sache zu tun? (baz
ist ein konstanter Ausdruck sowieso)auch constexpr ist nötig, wenn das Mitglied nicht eine
integral or enumeration type
aber sonst, ja, was zählt, ist, dass es ein konstanter Ausdruck.Im ersten Absatz der "ord-verwendet" sollte gelesen werden als "odr-used" ist, glaube ich, aber ich bin nie sicher, ob mit C++
InformationsquelleAutor Shafik Yaghmour
Dies ist wirklich ein Fehler im C++11 - wie andere bereits erklärt haben, in C++11 static constexpr member-variable, im Gegensatz zu jeder anderen Art von constexpr Globale variable, hat externe Bindung, so muss explizit definiert werden irgendwo.
Es ist auch erwähnenswert, dass können Sie in der Praxis Häufig Weg mit static constexpr-member-Variablen ohne Definitionen, die beim kompilieren mit der Optimierung, da Sie am Ende kann inline in alle nutzt, aber wenn Sie kompilieren, ohne Optimierung oft Ihr Programm nicht link. Das macht diese eine sehr häufige versteckte Falle - Ihr Programm kompiliert wird gut mit der Optimierung, aber sobald Sie deaktivieren der Optimierung (vielleicht für debugging), es nicht zu verlinken.
Gute Nachricht ist aber - dieser Fehler ist behoben in C++17! Der Ansatz ist ein wenig verworren aber: in C++17, static constexpr-member-Variablen werden, sind implizit inline. Mit inline angewendet, um die Variablen ist ein neues Konzept in C++17, aber es bedeutet effektiv, dass Sie nicht brauchen eine ausdrückliche definition überall.
InformationsquelleAutor SethML
Nicht die elegantere Lösung sein, die änderung der
char[]
in:Diese Art und Weise können wir die definition/Deklaration/Initialisierung in 1 Zeile code.
char[]
können Siesizeof
um die Länge des string zur compile-Zeit, mitchar *
Sie nicht (es wird wieder die Breite der Zeiger-Typ, 1 in diesem Fall).Diese erzeugt Warnung, wenn Sie möchten, zu streng sein mit ISO C++11.
Siehe meine Antwort, die nicht zeigen die
sizeof
Problem , und kann verwendet werden, in der "header-only" - LösungenInformationsquelleAutor deddebme
Mein workaround für die externe Bindung statische-Mitglieder ist die Nutzung
constexpr
Referenz-member-get - (was aber nicht das problem @gnzlbg hob als Kommentar zu der Antwort von @deddebme).Dieses idiom ist mir wichtig, weil ich ungern mehrere .cpp-Dateien in meine Projekte, und versuchen Sie, die Anzahl zu begrenzen, um eine, die aus nichts außer
#include
s und einemain()
Funktion.InformationsquelleAutor Josh Greifer
Auf meine Umgebung, gcc-Version ist 5.4.0. Hinzufügen "-O2" können dieses Problem beheben, Kompilierung Fehler. Es scheint gcc kann in diesem Fall behandeln, wenn Sie Fragen zur Optimierung.
InformationsquelleAutor Haishan Zhou