2009-08-21 7 views
6
struct A { 
    static const int a = 5; 

    struct B { 
     static const int b = a; 
    }; 

}; 

int main() { 
    return A::B::b; 
} 

Powyższy kod się kompiluje. Jednakże, jeśli przejdziesz do artykułu Effective C++ autorstwa Scotta Myersa (str. 14); Potrzebujemy definicji oprócz deklaracji. Czy ktoś może wyjaśnić, dlaczego jest to wyjątek?przy użyciu statycznego const int w struct/class

+1

Kod _does_ zawiera definicję "a". –

+2

Nie, nie zawiera definicji. –

+1

@ Henk. Nie całkiem. Spróbuj przekazać adres funkcji "a" lub "b" do funkcji i zobacz, jaki komunikat generuje kompilator! –

Odpowiedz

18

Kompilatory C++ dopuszczają, że statyczne liczby całkowite ze stałych (i tylko liczby całkowite) mają mieć określoną wartość w miejscu, w którym zostały zadeklarowane. Dzieje się tak, ponieważ zmienna zasadniczo nie jest potrzebna i żyje tylko w kodzie (zwykle jest kompilowana).

Inne typy zmiennych (takie jak static const char *) nie mogą być zwykle definiowane, gdy są zadeklarowane i wymagają osobnej definicji.

Aby uzyskać nieco więcej wyjaśnień, zdaj sobie sprawę, że uzyskanie dostępu do zmiennej globalnej zazwyczaj wymaga podania adresu w kodzie niższego poziomu. Ale twoja zmienna globalna jest liczbą całkowitą, której rozmiar jest zwykle wielkością adresu, a kompilator zdaje sobie sprawę, że nigdy się nie zmieni, więc po co zawracać sobie głowę dodawaniem abstrakcji wskaźnika?

+0

+1, dobra odpowiedź. Ale co jeśli "const" integers? Czy możemy określić ich wartość w klasie? – Alcott

+0

nie "liczby całkowite", tylko stała ekspresja – czxyl

18

Według naprawdę pedantycznych reguł, tak, twój kod potrzebuje definicji tej statycznej liczby całkowitej. Ale według praktycznych reguł i tego, co wszystkie kompilatory implementują, ponieważ tak właśnie mają być zasady C++ 03 - nie, nie potrzebujesz definicji.

Reguły dla takich stałych liczb całkowitych mają na celu umożliwienie pominięcia definicji, jeśli liczba całkowita jest używana tylko w takich sytuacjach, w których wartość jest natychmiast odczytywana, a element statyczny może być używany w wyrażeniach stałych.

W instrukcji return wartość elementu jest natychmiast odczytywana, więc można pominąć definicję statycznego stałego elementu całkowitoliczbowego, jeśli jest to jedyne użycie. Następująca sytuacja wymaga jednak zdefiniowania:

struct A { 
    static const int a = 5; 

    struct B { 
     static const int b = a; 
    }; 

}; 

int main() { 
    int *p = &A::B::b; 
} 

Nie ma tu żadnej wartości, ale zamiast tego jest pobierany jej adres. Dlatego intencją standardu C++ 03 jest zapewnienie definicji elementu podobnego do następującego w niektórych plikach implementacji.

const int A::B::b; 

Uwaga że rzeczywiste zasady występujące w C++ 03 Standardu mówi, że definicja nie jest wymagane tylko wtedy, gdy używana jest zmienna, gdzie stała wyrażenie jest wymagane. Zasada ta jednak, jeśli jest ściśle stosowana, jest zbyt rygorystyczna. Pozwoliłoby to tylko na pominięcie definicji sytuacji, takiej jak wymiary tablicy - ale wymagałoby definicji w takich przypadkach jak instrukcja return. Odpowiedni raport o usterkach to here.

Sformułowanie C++ 0x zostało zaktualizowane, aby uwzględnić to rozwiązanie raportu o usterce i zezwolić na pisanie kodu.

+0

Czy to oznacza, że ​​Walt W nie ma racji, gdy mówi: "Kompilatory C++ pozwalają na zdefiniowanie stałych liczb całkowitych (i tylko liczb całkowitych) w miejscu, w którym są zadeklarowane"? Myślałem tak jak on, że "statyczna const int a = 5;" oświadczenie było zarówno deklaracją, jak i definicją. Jeśli dobrze rozumiem, jest to tylko deklaracja bez żadnej definicji, a A :: a może być używane tylko w bardzo szczególnych przypadkach. Interesuje mnie ostatnie słowo ... – neuro

+0

Tak, on też jest w błędzie. To tylko deklaracja - to nie jest definicja. Jeśli odwołasz się do niego w przypadkach, które nie od razu odczytują wartość, potrzebna jest definicja. Wydaje się, że masz rację w swoim komentarzu. –

+0

Lepiej? Przypuszczam, że to nie było techniczne użycie "definicji" –

0

Ogólnie, większość (i ostatni) kompilatory C++ pozwalają static const int

po prostu szczęście, może nie. Spróbuj starszego kompilatora, takiego jak gcc 2.0, i będzie to stanowczo karać za mniejszą niż ładną wiadomość o błędzie.

1

Jeśli jednak spróbować potrójny operand bez „definiowania” consts statyczne, pojawi się błąd linkera w GCC 4x:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13795

Więc chociaż konstrukty jak int k = A::CONSTVAL; są nielegalne w obecnym standardzie, są obsługiwane. Ale operand trójskładnikowy nie jest. Niektórzy operatorzy są bardziej równi niż inni, jeśli dostaniesz mój dryf :)

Tyle za "luźne" zasady. Proponuję napisać kod zgodny ze standardem, jeśli nie chcesz niespodzianek.

Powiązane problemy