Czy ktoś może wyjaśnić, dlaczego następujący kod nie zostanie skompilowany? Przynajmniej na g ++ 4.2.4.
A co ciekawsze, dlaczego będzie się kompilować, gdy obsadzę MEMBER na int?
#include <vector>
class Foo {
public:
static const int MEMBER = 1;
};
int main(){
vector<int> v;
v.push_back( Foo::MEMBER ); // undefined reference to `Foo::MEMBER'
v.push_back( (int) Foo::MEMBER ); // OK
return 0;
}
Odpowiedzi:
Musisz gdzieś zdefiniować element statyczny (po definicji klasy). Spróbuj tego:
To powinno pozbyć się niezdefiniowanego odniesienia.
źródło
Problem pojawia się z powodu interesującego zderzenia nowych funkcji C ++ i tego, co próbujesz zrobić. Najpierw spójrzmy na
push_back
podpis:Oczekuje odwołania do obiektu typu
T
. W starym systemie inicjalizacji taki element istnieje. Na przykład następujący kod kompiluje się dobrze:Wynika to z faktu, że gdzieś istnieje obiekt, w którym jest zapisana ta wartość. Jeśli jednak przejdziesz na nową metodę określania stałych stałych statycznych, tak jak masz powyżej,
Foo::MEMBER
nie będzie już obiektem. Jest to stała, nieco podobna do:Ale bez problemów z makrem preprocesora (i z bezpieczeństwem typu). Oznacza to, że wektor, który oczekuje odniesienia, nie może go otrzymać.
źródło
(int)
rzutowaniu) zachodzi w jednostce tłumaczenia z doskonałą widocznością stałej iFoo::MEMBER
nie jest już używana odr . Jest to w przeciwieństwie do pierwszego wywołania funkcji, w którym odniesienie jest przekazywane i oceniane w innym miejscu.void push_back( const T& value );
?const&
może wiązać się z wartościami.Standard C ++ wymaga definicji statycznego elementu const, jeśli definicja jest w jakiś sposób potrzebna.
Definicja jest wymagana, na przykład jeśli używany jest jej adres.
push_back
przyjmuje parametr przez odniesienie do stałej, więc kompilator ściśle potrzebuje adresu członka i należy go zdefiniować w przestrzeni nazw.Kiedy jawnie rzutujesz stałą, tworzysz tymczasowy i jest to tymczasowy, który jest powiązany z referencją (na specjalnych zasadach w standardzie).
To naprawdę interesujący przypadek i naprawdę uważam, że warto poruszyć problem, aby zmienić standardowe std, aby zachować takie samo zachowanie dla stałego członka!
Chociaż w dziwny sposób można to postrzegać jako uzasadnione użycie jednoargumentowego operatora „+”. Zasadniczo wynikiem
unary +
jest wartość, dlatego obowiązują zasady wiązania wartości z referenami const i nie używamy adresu naszego statycznego członka const:źródło
push_back
byłoconst &
. Bezpośrednie użycie członka spowodowało, że członek został powiązany z referencją, co wymagało posiadania adresu. Jednak dodanie+
tworzy tymczasowy z wartością członka. Odwołanie następnie wiąże się z tym tymczasowym, zamiast wymagać od członka posiadania adresu.Aaa.h
Aaa.cpp
źródło
Nie mam pojęcia, dlaczego obsada działa, ale Foo :: MEMBER nie jest przydzielany do pierwszego załadowania Foo, a ponieważ nigdy go nie ładujesz, nigdy nie jest przydzielany. Gdybyś miał gdzieś odniesienie do Foo, prawdopodobnie by to zadziałało.
źródło
W przypadku C ++ 11 powyższe byłoby możliwe dla podstawowych typów as
constexpr
Część tworzy statyczny wyraz w przeciwieństwie do statycznej zmiennej - i która zachowuje się jak bardzo prostej definicji metody inline. Podejście to okazało się jednak nieco chwiejne w przypadku ciągów C-string wewnątrz klas szablonów.źródło
Odnośnie drugiego pytania: push_ref przyjmuje odniesienie jako parametr i nie możesz mieć odniesienia do statycznego elementu pamięci klasy / struktury. Po wywołaniu static_cast tworzona jest zmienna tymczasowa. Odniesienie do tego obiektu można przekazać, wszystko działa dobrze.
A przynajmniej tak powiedział mój kolega, który to rozwiązał.
źródło