2011-04-01 2 views
14

Я сбит с толком ошибкой компоновщика при использовании следующего кода:«статический сопзЬ Int» вызывает ошибку связывания (неопределенная ссылка)

// static_const.cpp -- complete code 
#include <vector> 

struct Elem { 
    static const int value = 0; 
}; 

int main(int argc, char *argv[]) { 
    std::vector<Elem> v(1); 
    std::vector<Elem>::iterator it; 

    it = v.begin(); 
    return it->value; 
} 

Однако это не удается при компоновке - как-то оно должно иметь символ для значения static const. "

$ g++ static_const.cpp 
/tmp/ccZTyfe7.o: In function `main': 
static_const.cpp:(.text+0x8e): undefined reference to `Elem::value' 
collect2: ld returned 1 exit status 

BTW, этот компилятор отлично с -O1 или лучше; но он все еще терпит неудачу в более сложных случаях. Я использую gcc версии 4.4.4 20100726 (Red Hat 4.4.4-13).

Любые идеи, что может быть неправильным с моим кодом?

+1

Возможный дубликат [Weird undefined символы статических констант внутри структуры/класса] (http://stackoverflow.com/questions/4891067/weird-undefined-symbols-of-static-constants-inside-a-struct- класс) – karlphillip

+0

Спасибо за полезную ссылку! В нем также показано альтернативное решение: struct Elem {enum {value = 0}; } ', что кажется довольно привлекательным. – hrr

+0

Возможный дубликат [C++ - определение статических константных целочисленных членов в определении класса] (http://stackoverflow.com/questions/3025997/c-defining-static-const-integer-members-in-class-definition) – ks1322

ответ

8

Если вы хотите инициализировать его внутри структуры, вы тоже можете это сделать:

struct Elem { 
    static const int value = 0; 
}; 

const int Elem::value; 
+0

Это круто! Оно работает. Не имеет смысла не инициализировать его в структуре (классе), если вы можете (знаете значение в этой точке), потому что в противном случае все возможные оптимизации будут потеряны. (т. е. передача 0 непосредственно, а не загрузка 0 из некоторого адреса памяти.) –

+0

Если это действительно const, есть альтернатива «enum hack», см. http://stackoverflow.com/questions/4891067/weird-undefined -symbols-of-static-constants-inside-a-struct-class. Проблемы также описаны там: до C++ 11 перечислений не имеют приличного типа типа 'int', поэтому std :: min, std :: make_pair и т. д. не угадают их аргумент шаблона ... –

5

Попробуйте записать его как

struct Elem { 
    static const int value; 
}; 

const int Elem::value = 0; 

etc 

.

+0

Это, к сожалению, не сработает, когда это значение является меткой в ​​инструкции switch. – Petr

+0

@Petr Извините, не уверен, что сказать вам там. Я не использовал C++ через несколько лет, поэтому я не знаю, характерно ли это для 'static const' или что. – jonsca

+1

Я должен был стать более ясным. Я попытался указать всем, кто читает вам ответ, что - хотя совершенно правильно - бывают случаи, когда это не сработает. Например, если вы хотите использовать 'значение' как метку в переключателе, например' switch (x) {значение case: break; } ' – Petr

2

Классные члены обычно должны быть определены вне класса (объявленного внутри, определенного снаружи) в одном блоке компиляции.

Я не помню, как это взаимодействует с встроенной инициализацией статических интегральных элементов const.

+1

см. Http://stackoverflow.com/questions/1312241/using-a-static-const-int-in-a-struct-class/1312267#1312267 –

+1

Не существует специального правила для случая, когда декларация имеет Инициализатор --- в соответствии со стандартом объявленный объект должен быть определен где-то, если он потенциально используется. На практике большинство компиляторов являются дефектными в этом отношении и будут генерировать ошибку только для определенных целей, а не для других, если определение отсутствует. (Какие из них никогда не указываются и обычно меняются в зависимости от уровня оптимизации.) –

1

Почему бы просто не сделать это?

return Elem::value; 

Но ответ заключается в том, что вы назначаете значение в декларации. Предполагается, что это работает для базовых типов, таких как int, и требуется только для сложных типов (например, для классов, например, если у вас есть строка вместо int). То, что я нашел на практике, это то, что это поразило или пропустило в зависимости от того, какую версию того компилятора вы используете. И, как вы узнали, какой уровень оптимизации.

+0

Это не решает проблему инициализации. Кроме того, попадание или промах часто означает неопределенное поведение. – jonsca

+4

То просто избегает вопроса, который он задает. –

+0

На самом деле я ответил на него. Я сказал, что то, что он делает, должно работать (т. Е. Нет ничего плохого), но на практике это не всегда работает. Кажется, он обнаружил, что один из таких случаев «не работает». –

2

Также см. this post: по сути, проблема в том, что каким-то образом компилятор заканчивает тем, что расширяет ваш код, беря адрес Elem :: value.

Смежные вопросы