Rozumiem, że C ++ pozwala na definiowanie statycznych elementów stałych wewnątrz klasy, o ile jest to typ całkowity.
Dlaczego więc poniższy kod powoduje błąd konsolidatora?
#include <algorithm>
#include <iostream>
class test
{
public:
static const int N = 10;
};
int main()
{
std::cout << test::N << "\n";
std::min(9, test::N);
}
Pojawia się błąd:
test.cpp:(.text+0x130): undefined reference to `test::N'
collect2: ld returned 1 exit status
Co ciekawe, jeśli wykomentuję wywołanie std :: min, kod kompiluje się i łączy w porządku (mimo że odwołanie do testu :: N również znajduje się w poprzednim wierszu).
Masz jakiś pomysł, co się dzieje?
Mój kompilator to gcc 4.4 w systemie Linux.
c++
static
declaration
definition
HighCommander4
źródło
źródło
char
możesz zdefiniować go jakoconstexpr static const char &N = "n"[0];
. Zwróć uwagę na&
. Myślę, że to działa, ponieważ ciągi literałów są definiowane automatycznie. Martwię się tym - może to zachowywać się dziwnie w pliku nagłówkowym między różnymi jednostkami tłumaczeniowymi, ponieważ łańcuch prawdopodobnie będzie znajdować się pod wieloma różnymi adresami.inline const int N = 10
, który według mojej wiedzy nadal ma magazyn zdefiniowany przez linker. W tym przypadku można również użyć słowa kluczowego wbudowanego, aby podać definicję zmiennej statycznej w teście definicji klasy.Odpowiedzi:
Rozumiem, że C ++ pozwala na definiowanie statycznych elementów stałych wewnątrz klasy, o ile jest to typ całkowity.
Masz trochę racji. Możesz inicjować statyczne całki stałe w deklaracji klasy, ale to nie jest definicja.
http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/cplr038.htm
Co ciekawe, jeśli wykomentuję wywołanie std :: min, kod kompiluje się i łączy w porządku (mimo że odwołanie do testu :: N również znajduje się w poprzednim wierszu).
Masz jakiś pomysł, co się dzieje?
std :: min przyjmuje parametry przez odwołanie do stałej. Gdyby wziąć je według wartości, nie miałbyś tego problemu, ale ponieważ potrzebujesz odniesienia, potrzebujesz również definicji.
Oto rozdział / werset:
9.4.2 / 4 - Jeśli element
static
członkowski danych jest typuconst
całkowego lubconst
wyliczeniowego, jego deklaracja w definicji klasy może określać inicjalizator stałej, który powinien być całkowym wyrażeniem stałym (5.19). W takim przypadku element członkowski może pojawić się w całkowitych wyrażeniach stałych. Element członkowski powinien być nadal zdefiniowany w zakresie przestrzeni nazw, jeśli jest używany w programie, a definicja zakresu przestrzeni nazw nie powinna zawierać inicjatora .Zobacz odpowiedź Chu, aby uzyskać możliwe obejście.
źródło
5
do aconst int&
. Dlaczego więc nie traktować POtest::N
jako odpowiedniego dosłownego?Przykład Bjarne Stroustrupa w jego C ++ FAQ sugeruje, że masz rację i potrzebujesz definicji tylko wtedy, gdy bierzesz adres.
Mówi: „Możesz wziąć adres statycznego elementu członkowskiego, jeśli (i tylko wtedy) ma on definicję spoza klasy” . Co sugeruje, że działałoby inaczej. Może twoja funkcja min wywołuje adresy zza kulis.
źródło
std::min
przyjmuje parametry przez odniesienie, dlatego wymagana jest definicja.template<class K, class V, class C> const typename AE<K,V,C>::KeyContainer::size_type AE<K,V,C>::c7;
gdzie KeyContainer jest typedef z std :: vector <K>. Należy wymienić wszystkie parametry szablonu i wpisać nazwę typu, ponieważ jest to typ zależny. Może komuś ten komentarz przyda się. Jednak teraz zastanawiam się, jak wyeksportować to w bibliotece DLL, ponieważ klasa szablonu jest oczywiście w nagłówku. Czy muszę wyeksportować c7 ???Innym sposobem, aby to zrobić, w każdym razie w przypadku typów całkowitych, jest zdefiniowanie stałych jako wyliczeń w klasie:
źródło
Nie tylko int. Ale nie możesz zdefiniować wartości w deklaracji klasy. Jeśli masz:
w pliku .h musisz mieć:
w pliku .cpp.
źródło
static const
integralnego elementu członkowskiego w definicji klasy. Ale to wciąż nie definiuje tego członka. Zobacz odpowiedź Noah Robertsa po szczegóły.Oto inny sposób obejścia tego problemu:
(Myślę, że odpowiedź Szalonego Eddiego poprawnie opisuje, dlaczego problem istnieje).
źródło
std::min(9, +test::N);
Od C ++ 11 możesz używać:
static constexpr int N = 10;
Teoretycznie nadal wymaga to zdefiniowania stałej w pliku .cpp, ale dopóki nie weźmiesz jej adresu
N
, jest bardzo mało prawdopodobne, że jakakolwiek implementacja kompilatora spowoduje błąd;).źródło
Nie, 3.1 §2 mówi:
źródło