Undefined ссылка на статический член класса - программирование
Подтвердить что ты не робот

Undefined ссылка на статический член класса

Может кто-нибудь объяснить, почему следующий код не будет компилироваться? По крайней мере, на g++ 4.2.4.

И что еще интереснее, почему он будет компилироваться, когда я делаю MEMBER в 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;
}
4b9b3361

Ответ 1

Вам нужно определить статический член где-нибудь (после определения класса). Попробуйте следующее:

class Foo { /* ... */ };

const int Foo::MEMBER;

int main() { /* ... */ }

Это должно избавиться от ссылки undefined.

Ответ 2

Проблема возникает из-за интересного столкновения новых функций С++ и того, что вы пытаетесь сделать. Во-первых, давайте посмотрим на подпись 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;
}

Это потому, что есть фактический объект где-то, у которого есть это значение, хранящееся в нем. Если, однако, вы переключитесь на новый метод указания статических константных членов, как вы уже выше, Foo::MEMBER больше не является объектом. Это постоянная, несколько сродни:

#define MEMBER 1

Но без головных болей макроса препроцессора (и с безопасностью типа). Это означает, что вектор, ожидающий ссылки, не может получить его.

Ответ 3

Стандарт С++ требует определения для вашего статического члена-константы, если определение так или иначе необходимо.

Требуется определение, например, если используется адрес. push_back принимает свой параметр с помощью ссылки const, и поэтому строгому компилятору нужен адрес вашего члена, и вам нужно определить его в пространстве имен.

Когда вы явно используете константу, вы создаете временную, и это временная привязка к ссылке (по специальным правилам в стандарте).

Это действительно интересный случай, и я на самом деле думаю, что стоит поднимать проблему, чтобы std изменился, чтобы иметь такое же поведение для вашего постоянного члена!

Хотя, странным образом это можно рассматривать как законное использование унарного оператора "+". В основном результат unary + является rvalue, поэтому применяются правила привязки ссылок rvalues ​​к const, и мы не используем адрес нашего статического члена const:

v.push_back( +Foo::MEMBER );

Ответ 4

Aaa.h

class Aaa {

protected:

    static Aaa *defaultAaa;

};

Aaa.cpp

// You must define an actual variable in your program for the static members of the classes

static Aaa *Aaa::defaultAaa;

Ответ 5

Не знаю, почему работает бросок, но Foo:: MEMBER не выделяется до тех пор, пока Foo не будет загружен, и поскольку вы никогда не загружаете его, он никогда не выделяется. Если бы вы где-то ссылались на Foo, это, вероятно, сработало бы.

Ответ 6

В отношении второго вопроса: push_ref принимает ссылку как параметр, и вы не можете иметь ссылку на static const memeber класса /struct. После вызова static_cast создается временная переменная. И ссылка на этот объект может быть передана, все работает нормально.

Или, по крайней мере, мой коллега, который решил это, сказал.

Ответ 7

С С++ 11 приведенное выше возможно для базовых типов как

class Foo {
public:  
  static constexpr int MEMBER = 1;  
};

Часть constexpr создает статическое выражение в отличие от статической переменной - и это ведет себя так же, как чрезвычайно простое определение встроенного метода. Тем не менее подход оказался немного шатким с C-string constexprs внутри классов шаблонов.