Может кто-нибудь объяснить, почему следующий код не скомпилируется? По крайней мере, на 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;
}
Ответы:
Вам нужно где-то определить статический член (после определения класса). Попробуй это:
Это должно избавить от неопределенной ссылки.
источник
Проблема возникает из-за интересного столкновения новых функций C ++ и того, что вы пытаетесь сделать. Во-первых, давайте посмотрим на
push_back
подпись:Ожидается ссылка на объект типа
T
. При старой системе инициализации такой член существует. Например, следующий код компилируется просто отлично:Это потому, что где-то есть реальный объект, в котором хранится это значение. Если, однако, вы переключаетесь на новый метод указания статических константных членов, как у вас выше,
Foo::MEMBER
больше не является объектом. Это константа, несколько сродниНо без головной боли макроса препроцессора (и с безопасностью типа). Это означает, что вектор, ожидающий ссылку, не может его получить.
источник
(int)
приведению) происходит в блоке перевода с идеальной видимостью константы иFoo::MEMBER
больше не используется odr . Это отличается от первого вызова функции, где ссылка передается и оценивается в другом месте.void push_back( const T& value );
?const&
Можно связать со значениями.Стандарт C ++ требует определения вашего статического константного члена, если определение как-то необходимо.
Требуется определение, например, если используется его адрес.
push_back
принимает его параметр по константной ссылке, поэтому компилятору строго необходим адрес вашего члена, и вам нужно определить его в пространстве имен.Когда вы явно приводите константу, вы создаете временный объект, и именно этот временный объект привязывается к ссылке (в соответствии со специальными правилами в стандарте).
Это действительно интересный случай, и я на самом деле думаю, что стоит поднять проблему, чтобы стандартное поведение было изменено таким же образом для вашего постоянного члена!
Хотя странным образом это можно рассматривать как законное использование унарного оператора «+». В основном результатом
unary +
является значение rvalue, поэтому применяются правила привязки значений rvalue к ссылкам const, и мы не используем адрес нашего статического члена const:источник
push_back
былconst &
. Непосредственное использование члена привело к тому, что член был привязан к ссылке, для которой требовался адрес. Тем не менее, добавление+
создает временное значение члена. Ссылка затем связывается с этим временным, а не требует, чтобы член имел адрес.Aaa.h
Aaa.cpp
источник
Не знаю, почему работает приведение, но Foo :: MEMBER не выделяется до тех пор, пока Foo не загрузится в первый раз, и, поскольку вы никогда не загружаете его, он никогда не выделяется. Если бы у вас была ссылка на Foo где-то, это, вероятно, сработало бы.
источник
С C ++ 11, выше было бы возможно для основных типов, как
Эта
constexpr
деталь создает статическое выражение, а не статическую переменную, и это ведет себя как очень простое определение встроенного метода. Однако этот подход оказался немного шатким, когда в классах шаблонов использовались константные выражения C-строки.источник
Что касается второго вопроса: push_ref принимает ссылку в качестве параметра, и вы не можете иметь ссылку на статический константный член класса / структуры. Как только вы вызываете static_cast, создается временная переменная. И ссылку на этот объект можно передать, все работает просто отлично.
Или, по крайней мере, мой коллега, который решил это, сказал так.
источник