Dlaczego nie mogę zainicjować static
członków danych w klasie?
Standard C ++ pozwala na inicjowanie wewnątrz klasy tylko statycznych stałych typów całkowych lub wyliczeniowych. To jest powód, a
dla którego można inicjalizować, podczas gdy inne nie.
Odniesienie:
C ++ 03 9.4.2 Statyczne elementy członkowskie danych
§4
Jeśli statyczny element członkowski danych jest typu const integra lub const wyliczenia, jego deklaracja w definicji klasy może określać inicjator stałej, który powinien być wyrażeniem stałym integralnym (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.
Jakie są typy całkowite?
C ++ 03 3.9.1 Typy podstawowe
§7
Typy bool, char, wchar_t oraz typy całkowite ze znakiem i bez znaku są zbiorczo nazywane typami całkowitymi.43) Synonimem typu całkowitego jest typ całkowity.
Notatka:
43) Dlatego wyliczenia (7.2) nie są integralne; jednak wyliczenia mogą być promowane do int, unsigned int, long lub unsigned long, jak określono w 4.5.
Obejście:
Możesz użyć sztuczki wyliczeniowej, aby zainicjować tablicę wewnątrz definicji klasy.
class A
{
static const int a = 3;
enum { arrsize = 2 };
static const int c[arrsize] = { 1, 2 };
};
Dlaczego norma na to nie zezwala?
Bjarne wyjaśnia to trafnie tutaj :
Klasa jest zwykle deklarowana w pliku nagłówkowym, a plik nagłówkowy jest zwykle dołączany do wielu jednostek tłumaczeniowych. Jednak aby uniknąć skomplikowanych reguł konsolidatora, C ++ wymaga, aby każdy obiekt miał unikalną definicję. Ta reguła zostałaby złamana, gdyby C ++ pozwolił na definiowanie w klasie jednostek, które musiałyby być przechowywane w pamięci jako obiekty.
Dlaczego dozwolone są tylko static const
typy całkowite i wyliczenia In-class In-class?
Odpowiedź jest ukryta w cytacie Bjarne'a, przeczytaj go uważnie:
„C ++ wymaga, aby każdy obiekt miał unikalną definicję. Ta reguła zostałaby złamana, gdyby C ++ pozwolił na definiowanie w klasie encji, które musiały być przechowywane w pamięci jako obiekty”.
Zauważ, że tylko static const
liczby całkowite mogą być traktowane jako stałe czasu kompilacji. Kompilator wie, że wartość całkowita nie zmieni się w żadnym momencie i dlatego może zastosować własną magię i zastosować optymalizacje, kompilator po prostu wstawia takie elementy klasy, tj. Nie są już przechowywane w pamięci, ponieważ potrzeba przechowywania w pamięci jest usunięta , daje takim zmiennym wyjątek od reguły wspomnianej przez Bjarne'a.
Warto zauważyć, że nawet jeśli static const
wartości całkowite mogą mieć inicjalizację w klasie, przyjmowanie adresu takich zmiennych jest niedozwolone. Można wziąć adres statycznego elementu członkowskiego, jeśli (i tylko wtedy) ma on definicję spoza klasy. To dodatkowo potwierdza powyższe rozumowanie.
wyliczenia są dozwolone, ponieważ wartości typu wyliczeniowego mogą być używane tam, gdzie oczekuje się wartości int. patrz cytat powyżej
Jak to się zmienia w C ++ 11?
C ++ 11 łagodzi to ograniczenie do pewnego stopnia.
C ++ 11 9.4.2 Statyczne składowe danych
§3
Jeśli statyczny element członkowski danych ma typ literału const, jego deklaracja w definicji klasy może określać inicjator nawiasu klamrowego lub równego, w którym każda klauzula inicjatora, która jest wyrażeniem przypisania, jest wyrażeniem stałym. Statyczny element członkowski danych typu literał może być zadeklarowany w definicji klasy z wartością, constexpr specifier;
jeśli tak, jego deklaracja powinna określać inicjator nawiasu klamrowego lub równego, w którym każda klauzula inicjalizatora, która jest wyrażeniem przypisaniawyrażeniem stałym. [Uwaga: w obu tych przypadkach element członkowski może pojawić się w stałych wyrażeniach. —Nuta końcowa] Element członkowski powinien nadal być zdefiniowany w zakresie przestrzeni nazw, jeśli jest używany w programie, a definicja zakresu przestrzeni nazw nie powinna zawierać inicjatora.
Ponadto, C ++ 11 będzie pozwalają (§12.6.2.8) non-static członek dane mają być zainicjowana w którym jest zadeklarowana (w swojej klasie). Będzie to oznaczać dużo łatwą semantykę użytkownika.
Zauważ, że te funkcje nie zostały jeszcze zaimplementowane w najnowszej wersji gcc 4.7, więc nadal możesz otrzymywać błędy kompilacji.