与定义的类相同类型的静态constexpr成员

时间:2012-08-13 04:08:00

标签: c++ c++11 constexpr

我希望C类有一个类型为C的静态constexpr成员。这在C ++ 11中是否可行?

尝试1:

struct Foo {
    constexpr Foo() {}
    static constexpr Foo f = Foo();
};
constexpr Foo Foo::f;

g ++ 4.7.0说:“无效使用不完整类型”是指Foo()来电。

尝试2:

struct Foo {
    constexpr Foo() {}
    static constexpr Foo f;
};
constexpr Foo Foo::f = Foo();

现在问题是在类定义中缺少constexpr成员f的初始值设定项。

尝试3:

struct Foo {
    constexpr Foo() {}
    static const Foo f;
};
constexpr Foo Foo::f = Foo();

现在g ++抱怨Foo::f的{​​{1}}重新声明不同。

3 个答案:

答案 0 :(得分:32)

如果我正确地解释了标准,那是不可能的。

  

(§9.4.2/ 3)[...]文字类型的静态数据成员可以在中声明   使用constexpr说明符的类定义;如果是这样,它的声明应指定一个大括号或等于初始化器,其中作为赋值表达式的每个initializer子句都是一个常量表达式。 [...]

从上面(以及静态数据成员声明中没有关于非文字类型的单独声明的事实),我认为constexpr的静态数据成员必须文字类型(如§3.9/ 10中所定义),必须在声明中包含定义。使用以下代码可以满足后一条件:

struct Foo {
  constexpr Foo() {}
  static constexpr Foo f {};
};

类似于您的尝试1,但没有类外部定义。

但是,由于Foo在声明/定义静态成员时不完整,编译器无法检查它是否是文字类型(如§3.9/ 10中所定义),因此它拒绝代码。

请注意,this post-C++-11 document (N3308)讨论了标准中constexpr当前定义的各种问题,并提出修改建议。具体而言,“建议的措辞”部分建议对§3.9/ 10进行修订,这意味着将不完整类型作为一种文字类型。如果要将该修正案纳入标准的未来版本,您的问题将得到解决。

答案 1 :(得分:11)

我认为GCC拒绝您的尝试3是不正确的.C ++ 11标准(或其任何已接受的缺陷报告)中没有规则表明变量的重新声明必须为constexpr iff先前的声明是。最接近该规则的标准是 [dcl.constexpr](7.1.5)/ 1 _

  

如果函数或函数模板的任何声明具有constexpr指定符,则其所有声明都应包含constexpr指定符。

Clang的constexpr实施接受了你的尝试3。

答案 2 :(得分:7)

Richard Smith's answer上的更新,现在尝试3在GCC 4.9和5.1以及clang 3.4上编译。

struct Foo {
  std::size_t v;
  constexpr Foo() : v(){}
  static const Foo f;
};

constexpr const Foo Foo::f = Foo();

std::array<int, Foo::f.v> a;

然而,当Foo是一个类模板时,clang 3.4失败,但GCC 4.9和5.1仍然正常工作:

template < class T >
struct Foo {
  T v;
  constexpr Foo() : v(){}
  static const Foo f;
};

template < class T >
constexpr const Foo<T> Foo<T>::f = Foo();

std::array<int, Foo<std::size_t>::f.v> a; // gcc ok, clang complains

Clang错误:

error: non-type template argument is not a constant expression
std::array<int, Foo<std::size_t>::f.v> a;
                ^~~~~~~~~~~~~~~~~~~~~