在类模板中正确初始化静态constexpr数组?

mon*_*506 16 c++ templates static-members constexpr c++11

由于标准的措辞,C++中的静态类成员给我带来了一点混乱:

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];
Run Code Online (Sandbox Code Playgroud)

这是正确的语法吗?特别是在定义中使用模板感觉很尴尬,但GCC似乎正确地将所有内容联系起来.

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

arr*_*sea 13

如果它可以帮助任何人,以下使用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
Run Code Online (Sandbox Code Playgroud)

我没有声称这是否"合适".我会留给那些更有资格的人.

  • 我需要一个constexpr结构. (2认同)

eca*_*mur 11

我想你想要9.4.2p3:

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

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

template<class T> class X {
  static T s;
};
template<class T> T X<T>::s = 0;
Run Code Online (Sandbox Code Playgroud)

但是,如上所述constexpr static或其const static内部声明指定初始化程序的成员不应在其命名空间作用域定义中具有初始化程序,因此语法变为:

template<class T> class X {
  const static T s = 0;
};
template<class T> T X<T>::s;
Run Code Online (Sandbox Code Playgroud)

与非数组(即整数或枚举)静态constexpr数据成员的区别在于它在左值到右值转换中的使用不是使用odr的; 如果获取地址或形成一个const引用,你只需要定义它.

  • @ monkey_05_06正好; 3.2p3表示变量"x"的使用出现*除非*`x`"满足出现在常量表达式中的要求",即它是整数`const`或literal`constexpr`. (2认同)