Ошибка компоновщика C ++ с classом static constexpr

Я компилирую следующую простую программу с g++-4.6.1 --std=c++0x :

 #include  struct S { static constexpr int X = 10; }; int main() { return std::min(S::X, 0); }; 

Я получаю следующую ошибку компоновщика:

 /tmp/ccBj7UBt.o: In function `main': scratch.cpp:(.text+0x17): undefined reference to `S::X' collect2: ld returned 1 exit status 

Я понимаю, что встроенные в static статические члены не имеют определенных символов, но я был под (вероятно, ошибочным) впечатлением, что использование constexpr подсказывало компилятору всегда рассматривать символ как выражение; поэтому компилятор будет знать, что не имеет права передавать ссылку на символ S::X (по той же причине вы не можете взять ссылку на литерал 10 ).

Однако, если S объявлено как пространство имен, то есть «пространство имен S» вместо «struct S», все ссылки отлично.

Является ли это ошибкой g++ или мне все еще нужно использовать трюк, чтобы обмануть это раздражение?

Я не думаю, что это ошибка. Если вы меняете constexpr на const , он все равно терпит неудачу, с той же ошибкой.

Вы объявили S::X , но не определили его нигде, поэтому для него нет хранилища. Если вы делаете что-либо с этим, чтобы знать адрес, то вам также нужно определить его.

Примеры:

 int main() { int i = S::X; // fine foo(); // fine const int *p = &S::X; // needs definition return std::min(S::X, 0); // needs it also } 

Причиной этого является то, что constexpr может быть оценен во время компиляции, но его не обязательно оценивать как таковое и он может также выполняться во время выполнения. Он не инструктирует «компилятор всегда относиться к символу как к выражению» , он намекает, что было бы разумно и допустимо сделать это, если бы компилятор почувствовал это.

Причина ошибки уже объяснена, поэтому я просто добавлю обходной путь.

 return std::min(int(S::X), 0); 

Это создает временную, поэтому std::min может ссылаться на нее.

В стандарте C ++ ( последний рабочий проект ) говорится:

Имя, имеющее область пространства имен (3.3.6), имеет внутреннюю связь, если оно является именем […] переменной, которая явно объявлена ​​как const или constexpr и ни одно из явно объявленных extern или ранее объявленных иметь внешнюю связь […] ,

«Связь» определяется следующим образом:

Говорят, что имя имеет связь, когда он может обозначать один и тот же объект, ссылку, функцию, тип, шаблон, пространство имен или значение как имя, введенное декларацией в другой области:

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

– Если имя имеет внутреннюю связь , обозначаемый объект может ссылаться на имена из других областей в одной и той же единицы перевода.

– Если имя не имеет привязки , объект, который он обозначает, не может ссылаться на имена из других областей.

Таким образом, в случае namespace S он будет иметь внешнюю связь , в случае struct S он будет иметь внутреннюю связь .

Символы с внешней связью должны иметь явно определенный символ в некоторой единицы перевода.

Ваше понимание constexpr неверно. constexpr объявленный constexpr , все еще является lvalue, а функция, объявленная constexpr по-прежнему является функцией. И когда функция имеет ссылочный параметр и передается значение lvalue, язык требует, чтобы ссылка ссылалась на это значение lvalue и ничего больше. (При применении к переменной типа int разница между constexpr и plain const очень мала.)

Вам также необходимо предоставить определение для члена constexpr вне структуры (или classа), но на этот раз без его значения. См. Здесь: https://en.cppreference.com/w/cpp/language/static

 #include  struct S { static constexpr int X = 10; }; constexpr int S::X; int main() { return std::min(S::X, 0); }; 
  • Как включить OpenSSL в проект Qt
  • Как указать предпочтение пути библиотеки?
  • Связывание статических библиотек с другими статическими библиотеками
  • ошибка LNK2005: xxx, уже определенная в MSVCRT.lib (MSVCR100.dll) C: \ something \ LIBCMT.lib (setlocal.obj)
  • Ошибка связи C ++ после обновления до Mac OS X 10.9 / Xcode 5.0.1
  • g ++ неопределенная ссылка на typeinfo
  • вопросы об управлении именами в C ++
  • Встраивание DLL в скомпилированный исполняемый файл
  • Связывание libssl и libcrypto в GCC
  • Как сделать полностью статически связанную .exe с Visual Studio Express 2005?
  • Неопределенная ссылка на «initscr» Ncurses
  • Interesting Posts

    Django: установить внешний ключ с помощью целого числа?

    удалять идентификаторы, которые встречаются x раз R

    Проблема с вариацией C #: присвоение списка в виде списка

    Функция с отсутствующим возвратным значением, поведение во время выполнения

    Как добавить теги в файлы в Windows 7, чтобы они отображались в результатах поиска

    Невозможно открыть эмулятор WP8 в Visual Studio (открытие из работы менеджера Hyper-V)

    Почему #include не требуется использовать printf ()?

    Сколько символов может кодировать UTF-8?

    Как включить междоменный запрос на сервере?

    Linux – установка устройства с конкретными правами пользователя

    Каково первое целое число, которое плавающий IEEE 754 не может точно представлять?

    Используйте PowerShell для запуска сканирования вирусов на нескольких серверах

    CardView layout_width = “match_parent” не соответствует родительской ширине RecyclerView

    Каков хороший способ обрезать все символы пробелов из строки в T-SQL без UDF и без CLR?

    В выражении If-Else для возврата метода, если Else должно быть явно указано, если вместо него можно неявно следовать?

    Давайте будем гением компьютера.