链接器错误(未定义的引用)与`static constexpr const char *`和perfect-forwarding

时间:2015-03-03 18:52:19

标签: c++ linker c++14 constexpr perfect-forwarding

#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.o

  

/tmp/code-a049fe.o:在函数`SomeStruct :: SomeStruct()'中:   ./code.cpp:(.text._ZN10SomeStructC2Ev[_ZN10SomeStructC2Ev]+0xa):   未命名的引用`SomeStruct :: someString'clang:错误:链接器   命令失败,退出代码为1(使用-v查看调用)


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

  

/tmp/ccyrTsjS.o:在函数`SomeStruct :: SomeStruct()'中:   code.cpp :( text._ZN10SomeStructC2Ev [_ZN10SomeStructC5Ev] + 0xd中):   未定义的引用`SomeStruct :: someString'colle2:error:ld   返回1退出状态


为什么会发生此链接器错误?在编译时不应该someString可以解析吗?

此外,如果print(someString)替换为cout << someString;

,则不会发生错误

2 个答案:

答案 0 :(得分:5)

因为您正在参考该变量是使用了odr,这需要一个不符合要求的定义:

constexpr const char* SomeStruct::someString;

see it working live

从草案C ++ 14标准部分3.2 [basic.def.odr]

  

变量x的名称显示为潜在评估的表达式ex,除非应用,否则由ex使用   左值到右值的转换(4.1)到x产生一个不调用任何非平凡的常量表达式(5.20)   函数,如果x是一个对象,ex是表达式e的潜在结果集的一个元素,   将左值到右值转换(4.1)应用于e,或者e是丢弃值表达式[...]

例如,以下备选print不会使用someString

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

答案 1 :(得分:2)

在一系列情况下,您可能无法定义static数据成员(无论是否为constexpr,以及是否利用此初始化表单),这不是其中之一,因为你间接获取它的地址(因此它必须作为内存中的实际对象存在)。

您可以将其视为一个静态数据成员,由于使用的是什么而无法简单地在其使用时“内联”。

定义someString