2015-03-03 3 views
2
#include <iostream> 
using namespace std; 

template<typename T> void print(T&& mX) 
{ 
    std::cout << std::forward<T>(mX) << std::endl; 
} 

struct SomeStruct 
{ 
    static constexpr const char* someString{"hello!"}; 
    SomeStruct() 
    { 
     print(someString); 
    } 
}; 

int main() 
{ 
    SomeStruct s{}; 
    return 0; 
} 

clang++ -std=c++1y ./code.cpp -o code.oLinker ошибка (неопределенная ссылка) с `статической constexpr сопзИте полукокс *` и идеально-экспедиторской

/tmp/code-a049fe.o: In function `SomeStruct::SomeStruct()': ./code.cpp:(.text._ZN10SomeStructC2Ev[_ZN10SomeStructC2Ev]+0xa): undefined reference to `SomeStruct::someString' clang: error: linker command failed with exit code 1 (use -v to see invocation)


g++ -std=c++1y ./code.cpp -o code.o

/tmp/ccyrTsjS.o: In function `SomeStruct::SomeStruct()': code.cpp:(.text._ZN10SomeStructC2Ev[_ZN10SomeStructC5Ev]+0xd): undefined reference to `SomeStruct::someString' collect2: error: ld returned 1 exit status


Почему эта ошибка компоновщика происходит? Разве не someString должен быть разрешен во время компиляции?

Кроме того, ошибка не происходит, если print(someString) заменяется cout << someString;

+0

Почему вы пересылаете значение cout? – Tafuri

+2

Вы привязываете ссылку на 'someString', которая использует odr. Таким образом, его определение требуется. – 0x499602D2

+1

@Tafuri: это всего лишь минимальный пример для воспроизведения более сложной проблемы в более крупном проекте. –

ответ

3

Поскольку вы принимаете ссылку переменная УСО-используется, и это требует определения из линии:

constexpr const char* SomeStruct::someString; 

see it working live.

из проекта C++ 14 стандартный раздел 3.2[basic.def.odr]:

A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.20) that does not invoke any nontrivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression [...]

Например, следующий альтернативный print бы не ODR-использования someString:

template<typename T> void print(T mX) 
{ 
    std::cout << mX << std::endl; 
} 
2

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

Вы можете подумать об этом как о статическом элементе данных, который не может быть просто «встроен» в точку его использования, из-за , что, которым пользуется.

someString.

+0

Спасибо. Является ли 'static constexpr const char *' ближайшей вещью к возможному «static constexpr StringKnownAtCompileTimeType», или есть способ фактически сказать компилятору и людям, которые читают мой код, что я хочу строку, известную во время компиляции ? –

+0

@ VittorioRomeo: Он известен во время компиляции. Но вы не можете воспользоваться этим с помощью кода, который вы нам показали. –