为什么constexpr静态成员(类型类)需要定义?

oli*_*bre 10 c++ static-members constexpr c++11 c++14

==>查看coliru上的完整代码段和编译.

我有一个LiteralType类填充constexpr要求:

struct MyString
{
    constexpr MyString(char const* p, int s) : ptr(p), sz(s) {}
    constexpr char const* data() const { return ptr; }
    constexpr int         size() const { return sz;  }

    char const *ptr = 0;
    int  const  sz  = 0;
};
Run Code Online (Sandbox Code Playgroud)

我用它作为constexpr static成员变量:

struct Foo
{
    int size() { return str_.size(); }

    constexpr static MyString str_{"ABC",3};
};

int main()
{
  Foo foo;
  return ! foo.size();
}
Run Code Online (Sandbox Code Playgroud)

但链接器说:(
Clang-3.5和GCC-4.9)

undefined reference to `Foo::str_'
Run Code Online (Sandbox Code Playgroud)

我要定义constexpr static会员!
(我没有指定构造函数参数)

constexpr MyString Foo::str_;
Run Code Online (Sandbox Code Playgroud)

但是,如果constexpr static成员是int成员,则不必在类定义之外定义成员.这是我的理解,但我不确定......

问题:

  • 为什么int不需要在类声明之外定义但MyString需要这个?
  • constexpr static在头文件中定义成员是否有缺点?
    (我只提供我的库作为头文件)

Sha*_*our 5

一个定义规则告诉我们,我们不能有一个以上的定义ODR使用的程序中的变量.因此,如果变量使用了odr,那么您需要定义它,但是您无法将其定义为头文件,因为它可能包含在整个程序中不止一次.错误使用违规不需要诊断消息,因此您可以违反此规则,编译器没有义务通知您.

在您的情况下,您确实使用了odr str_,并且您不能在头文件中包含该定义,因为这会违反一个定义规则,因为它可以在程序中包含多次.

值得注意的是,如果您已经完成了以下操作,则不会使用它:

return str_.size_;
Run Code Online (Sandbox Code Playgroud)

因此,您不需要定义变量,在某些示例中可能会产生一些奇怪的后果.我怀疑这真的能长期解决你的问题.

C++标准部分草案中涵盖了odr规则3.2,他们说:

变量x的名称显示为潜在评估的表达式ex,除非将lvalue-to-rvalue转换(4.1)应用于x,否则将生成不调用任何非平凡函数的常量表达式(5.19),并且如果x是一个对象,ex是表达式e的潜在结果集合的元素,其中左值到右值的转换(4.1)应用于e,或者e是丢弃值表达式(第5节).如果它看起来像是一个潜在评估的表达式(包括作为非静态成员函数体内隐式转换的结果(9.3.1)),则使用这种情况.[...]

因此str_产生一个常量表达式,lvalue-to-rvalue转换不应用于表达式,str_.size()并且它不是废弃的值表达式,因此它是odr-used,因此str_需要定义.

另一方面,左值到右值的转换应用于表达式str_.size_,因此它不会使用,也不需要str_定义.