Этот код не работает или есть ошибка в g ++? - PullRequest
21 голосов
/ 11 июля 2011

По какой-то странной причине g ++ (версии 4.5.0 и 4.5.2) не может скомпилировать этот код:

bool somefunc() {
    return false;
}

class C {
  public:
    static const int a = 0;
    static const int b = 1;
};

class myclass {
  public:
    int check() {
        return somefunc() ? C::a : C::b;
        // if(somefunc()) return C::a; else return C::b;
    }
};

int main() {
    myclass obj;
    obj.check();
    return 0;
}

Это дает мне такую ​​ошибку:

/tmp/ccyvvTUy.o:/home/mati/test.cpp:14: undefined reference to `C::a'
/tmp/ccyvvTUy.o:/home/mati/test.cpp:14: undefined reference to `C::b'
collect2: ld returned 1 exit status

Что странно, еслиЯ заменяю проблемную строку на закомментированную строку, она прекрасно компилируется.Что-то не так с моим кодом и что-то, чего я не понимаю в C ++, или это просто ошибка в G ++?

Ответы [ 4 ]

18 голосов
/ 11 июля 2011

В настоящее время ведутся дебаты о том, является ли этот код действительным или нет .

В любом случае, согласно некоторым прочтениям, константы фактически делают должны быть определены перед использованием, а не только объявлены.То есть,

class C {
  public:
    static const int a = 0;
    static const int b = 1;
};

const int C::a;
const int C::b;

Или просто используйте хак enum, который использовался для размещения старых компиляторов (но который в конце концов может быть единственным законным способом):

class C {
  public:
    enum { a = 0, b = 1 };
};
5 голосов
/ 11 июля 2011

См. 9.4.2 / 4:

Если член статических данных имеет константный интеграл или константный тип перечисления, его объявление в определении класса может указывать инициализатор константы, который должен быть константой интегралавыражение (5.19).В этом случае член может появляться в виде целочисленных константных выражений в своей области видимости.Элемент по-прежнему должен быть определен в области имен, если он используется в программе, и определение области имен не должно содержать инициализатора.

Существует некоторое противоречие (я полагаю) относительно точного значенияиз «используется», хотя я понимаю, что если программа требует адрес переменной, то она «используется» в этом контексте.На мой взгляд, совершенно необоснованно, что изменение троицы на if/else или изменение уровня оптимизации может изменить представление о программе, как это видно из g ++, что приведет к провалу или успеху.Также обратите внимание, что здесь ничего не говорится о необходимой диагностике, если вы нарушаете это требование.

Вы не можете ошибиться, всегда определяя свои статические элементы.

0 голосов
/ 12 июля 2011

изменить следующую строку вернуть somefunc ()? C :: a: C :: b;

в return (somefunc ()? C :: a: C :: b);

Должен скомпилироваться.

0 голосов
/ 11 июля 2011

Попробуйте определить его глобально без оптимизации.

const int C::a = 0; 
...