Nach meinem Verständnis können in C ++ statische const-Mitglieder innerhalb einer Klasse definiert werden, sofern es sich um einen Integer-Typ handelt.
Warum gibt mir der folgende Code dann einen Linkerfehler?
#include <algorithm>
#include <iostream>
class test
{
public:
static const int N = 10;
};
int main()
{
std::cout << test::N << "\n";
std::min(9, test::N);
}
Der Fehler, den ich bekomme, ist:
test.cpp:(.text+0x130): undefined reference to `test::N'
collect2: ld returned 1 exit status
Interessanterweise kompiliert und verknüpft der Code, wenn ich den Aufruf von std :: min auskommentiere, einwandfrei (obwohl auf test :: N auch in der vorherigen Zeile verwiesen wird).
Irgendeine Idee, was los ist?
Mein Compiler ist gcc 4.4 unter Linux.
c++
static
declaration
definition
HighCommander4
quelle
quelle
char
können Sie es stattdessen als definierenconstexpr static const char &N = "n"[0];
. Beachten Sie die&
. Ich denke, das funktioniert, weil Literal-Strings automatisch definiert werden. Ich mache mir allerdings ein bisschen Sorgen darüber - es könnte sich in einer Header-Datei zwischen verschiedenen Übersetzungseinheiten seltsam verhalten, da sich die Zeichenfolge wahrscheinlich an mehreren verschiedenen Adressen befindet.inline const int N = 10
, das meines Wissens immer noch einen Speicher hat, der irgendwo durch Linker definiert ist. Schlüsselwort inline könnte auch in diesem Fall verwendet werden , um statische Variable zu schaffen Definition innerhalb der Klassendefinition Tests.Antworten:
Nach meinem Verständnis können in C ++ statische const-Mitglieder innerhalb einer Klasse definiert werden, sofern es sich um einen Integer-Typ handelt.
Du bist irgendwie richtig. Sie dürfen statische const-Integrale in der Klassendeklaration initialisieren, dies ist jedoch keine Definition.
http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/cplr038.htm
Interessanterweise kompiliert und verknüpft der Code, wenn ich den Aufruf von std :: min auskommentiere, einwandfrei (obwohl auf test :: N auch in der vorherigen Zeile verwiesen wird).
Irgendeine Idee, was los ist?
std :: min nimmt seine Parameter als const-Referenz. Wenn sie nach Wert genommen würden, hätten Sie dieses Problem nicht, aber da Sie eine Referenz benötigen, benötigen Sie auch eine Definition.
Hier ist Kapitel / Vers:
9.4.2 / 4 - Wenn ein
static
Datenelement vomconst
Integral- oderconst
Aufzählungstyp ist, kann seine Deklaration in der Klassendefinition einen Konstanteninitialisierer angeben , der ein integraler Konstantenausdruck sein soll (5.19). In diesem Fall kann das Element in ganzzahligen konstanten Ausdrücken erscheinen. Das Mitglied muss weiterhin in einem Namespace-Bereich definiert sein, wenn es im Programm verwendet wird, und die Namespace-Bereichsdefinition darf keinen Initialisierer enthalten .Eine mögliche Problemumgehung finden Sie in Chus Antwort.
quelle
5
an a bindenconst int&
. Warum also nicht die OPstest::N
als das entsprechende Literal behandeln?Das Beispiel von Bjarne Stroustrup in seinen C ++ - FAQ legt nahe, dass Sie korrekt sind und nur dann eine Definition benötigen, wenn Sie die Adresse verwenden.
Er sagt : „Sie können die Adresse eines statischen Element nehmen , wenn (und nur dann) ist es eine out-of-Class - Definition hat“ . Was darauf hindeutet, dass es anders funktionieren würde. Vielleicht ruft Ihre Min-Funktion hinter den Kulissen Adressen auf.
quelle
std::min
nimmt seine Parameter als Referenz, weshalb eine Definition erforderlich ist.template<class K, class V, class C> const typename AE<K,V,C>::KeyContainer::size_type AE<K,V,C>::c7;
KeyContainer ein Typedef von std :: vector <K> ist. Man muss alle Vorlagenparameter auflisten und den Typnamen schreiben, da es sich um einen abhängigen Typ handelt. Vielleicht findet jemand diesen Kommentar hilfreich. Jetzt frage ich mich jedoch, wie ich dies in eine DLL exportieren soll, da sich die Vorlagenklasse natürlich in einem Header befindet. Muss ich c7 exportieren ???Eine andere Möglichkeit, dies für Ganzzahltypen zu tun, besteht darin, Konstanten als Aufzählungen in der Klasse zu definieren:
quelle
Nicht nur int's. Sie können den Wert jedoch nicht in der Klassendeklaration definieren. Wenn Sie haben:
In der .h-Datei müssen Sie dann haben:
in der CPP-Datei.
quelle
static const
Integralelement in der Klassendefinition angeben . Aber das definiert dieses Mitglied immer noch nicht . Siehe Noah Roberts Antwort für Details.Hier ist eine andere Möglichkeit, das Problem zu umgehen:
(Ich denke, Crazy Eddies Antwort beschreibt richtig, warum das Problem besteht.)
quelle
std::min(9, +test::N);
Ab C ++ 11 können Sie Folgendes verwenden:
static constexpr int N = 10;
Dies erfordert theoretisch immer noch, dass Sie die Konstante in einer CPP-Datei definieren, aber solange Sie nicht die Adresse
N
davon verwenden, ist es sehr unwahrscheinlich, dass eine Compiler-Implementierung einen Fehler erzeugt;).quelle
Nein, 3.1 §2 sagt:
quelle