在类模板中正确初始化静态constexpr数组? P>静态C++类成员由于标准的误读而引起了我的一点困惑:

在类模板中正确初始化静态constexpr数组? P>静态C++类成员由于标准的误读而引起了我的一点困惑:,c++,templates,c++11,static-members,constexpr,C++,Templates,C++11,Static Members,Constexpr,9.4.2静态数据成员[class.Static.data] 静态数据成员在其类定义中的声明不是定义 但是,constexpr需要在其声明(例如,在类定义中)处初始化(AFAIK,无法从标准中找到引用) 由于对constexpr的限制,我实际上忘记了在类之外定义静态成员的必要性,直到我尝试访问静态constexpr数组。提供了定义数组成员的正确方法,但我对类模板中此定义的含义感兴趣 这就是我的结局: template<typename T> class MyClass { priva

9.4.2静态数据成员[class.Static.data]

静态数据成员在其类定义中的声明不是定义

但是,constexpr需要在其声明(例如,在类定义中)处初始化(AFAIK,无法从标准中找到引用)

由于对constexpr的限制,我实际上忘记了在类之外定义静态成员的必要性,直到我尝试访问静态constexpr数组。提供了定义数组成员的正确方法,但我对类模板中此定义的含义感兴趣

这就是我的结局:

template<typename T>
class MyClass
{
private:
  static constexpr std::size_t _lut[256] = { /* ... */ };
  T _data;

public:
  static constexpr std::size_t GetValue(std::size_t n) noexcept
  {
    return _lut[n & 255];
  }

  // ...
};

template<typename T>
constexpr std::size_t MyClass<T>::_lut[256];
模板
类MyClass
{
私人:
静态constexpr std::size\u t\u lut[256]={/*…*/};
T_数据;
公众:
静态constexpr std::size\t GetValue(std::size\t n)无异常
{
返回_lut[n&255];
}
// ...
};
模板
constexpr std::size_t MyClass::_lut[256];
这是正确的语法吗?尤其是在定义中使用模板感觉很尴尬,但GCC似乎将所有内容都适当地链接起来


作为后续问题,是否应该类似地定义非数组静态constexpr成员(模板定义在类之外)?

我认为您需要9.4.2p3:

如果非易失性
const static
数据成员为整型或枚举型,则其在类定义中的声明可以指定一个大括号或相等的初始值设定项,其中作为赋值表达式的每个初始值设定项子句都是常量表达式(5.19)。可以使用
constexpr
说明符在类定义中声明文本类型的静态数据成员;如果是这样,其声明应指定一个大括号或相等的初始值设定项,其中作为赋值表达式的每个初始值设定项子句都是常量表达式。[…]如果程序中使用odr(3.2),则仍应在名称空间范围中定义成员,并且名称空间范围定义不应包含初始值设定项

模板静态数据成员的定义是模板声明(14p1)。14.5.1.3p1中给出的示例为:

template<class T> class X {
  static T s;
};
template<class T> T X<T>::s = 0;

与非数组(即整数或枚举)静态constexpr数据成员的区别在于,它在左值到右值转换中的使用不是odr使用;您只需要在获取其地址或形成对其的常量引用时定义它。

如果它能帮助任何人,以下内容适用于使用constexpr的GCC 4.7:

template<class T> class X {
  constexpr static int s = 0;
};
template<class T> constexpr int X<T>::s; // link error if this line is omitted
模板类X{
constexpr static int s=0;
};
模板constexpr int X::s;//如果省略此行,则链接错误

我不是在说这是否“合适”。我会把这个留给更有资格的人。

谢谢!编辑中添加了一些有用的内容!:)关于非数组成员,您的意思是,由于它是一个constexpr,因此实际上不必定义该成员(只要它确实是一个常量表达式,并且在这样的上下文中使用)?@monkey\u 05\u 06;3.2p3指出,除非
x
“满足出现在常量表达式中的要求”,否则变量
x
的odr使用会发生,即它是整型
const
或literal
constepr
。如果
模板T x::s
被省略,ODR灼伤了我的大脑,例如,起点:这里有一件令人困惑的事情:类中的声明不是定义,而是初始值设定项。类外的声明没有初始值设定项,但它是一个定义。这很容易混淆(至少IMHO),但constexpr规范要求初始值设定项位于声明点,而不是定义点。这可能与ODR处理常量表达式的方式有关(也就是说,constexpr成员不需要有定义,只要它只用于编译时常量表达式-请参阅ecatmur给出的答案)。我需要一个constexpr结构。
template<class T> class X {
  constexpr static int s = 0;
};
template<class T> constexpr int X<T>::s; // link error if this line is omitted