Неопределенная ссылка на статический член класса



может кто-нибудь объяснить, почему следующий код не компилируется? По крайней мере на 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;
}
973   7  

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

    Ничего не найдено.