Неопределенная ссылка на статический член класса
может кто-нибудь объяснить, почему следующий код не компилируется? По крайней мере на G++ 4.2.4.
и еще интереснее, почему он будет компилироваться, когда я приведу член в 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;
}
7 ответов:
вам нужно фактически определить статический член где-то (после определения класса). Попробуйте это:
class Foo { /* ... */ }; const int Foo::MEMBER; int main() { /* ... */ }Это должно избавиться от неопределенной ссылки.
проблема возникает из-за интересного столкновения новых функций C++ и того, что вы пытаетесь сделать. Во-первых, давайте взглянем на
push_backподпись:void push_back(const T&)он ожидает ссылку на объект типа
T. При старой системе инициализации такой член существует. Например, следующий код компилируется просто замечательно:#include <vector> class Foo { public: static const int MEMBER; }; const int Foo::MEMBER = 1; int main(){ std::vector<int> v; v.push_back( Foo::MEMBER ); // undefined reference to `Foo::MEMBER' v.push_back( (int) Foo::MEMBER ); // OK return 0; }это потому, что где-то есть фактический объект, в котором хранится это значение. Если, однако, вы переключитесь на новый метод указания статических членов const, как у вас есть выше,
Foo::MEMBERбольше не является объектом. Это константа, несколько сродни:#define MEMBER 1но без головных болей макроса препроцессора (и с безопасностью типа). Это означает, что вектор, который ожидает ссылку, не могу.
стандарт C++ требует определения для вашего статического члена const, если определение каким-то образом необходимо.
определение является обязательным, например, если используется его адрес.
push_backпринимает свой параметр по ссылке const, и поэтому строго компилятору нужен адрес вашего члена, и вам нужно определить его в пространстве имен.когда вы явно бросаете константу, вы создаете временную, и это временное, которое привязано к ссылке (по специальным правилам в стандарте).
Это действительно интересный случай, и я действительно думаю, что стоит поднять вопрос, чтобы std был изменен, чтобы иметь такое же поведение для вашего постоянного члена!
хотя, странным образом это можно рассматривать как законное использование унарного оператора'+'. В основном результат
unary +является rvalue и поэтому правила привязки rvalues к ссылкам const применяются, и мы не используем адрес нашего статического членов const:v.push_back( +Foo::MEMBER );
ААА.h
class Aaa { protected: static Aaa *defaultAaa; };ААА.cpp
// You must define an actual variable in your program for the static members of the classes static Aaa *Aaa::defaultAaa;
Не знаю, почему бросок работает, но Foo::MEMBER не выделяется до первого загрузки Foo, и поскольку вы никогда не загружаете его, он никогда не выделяется. Если бы у вас была ссылка на Foo где-то, это, вероятно, сработало бы.
Что касается второго вопроса: push_ref принимает ссылку в качестве параметра, и вы не можете иметь ссылку на статический const memeber класса/структуры. Как только вы вызываете метод static_cast, создается временная переменная. И ссылку на этот объект можно передать, все работает просто отлично.
или, по крайней мере, мой коллега, который решил это так сказал.
С C++11, выше было бы возможно для основных типов как
class Foo { public: static constexpr int MEMBER = 1; };The
constexprчасть создает статический выражение в отличие от статического переменная - и это ведет себя так же, как очень простое определение встроенного метода. Однако подход оказался немного шатким с помощью C-string constexprs внутри классов шаблонов.
Comments