繁体   English   中英

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

[英]static constexpr member of same type as class being defined

我希望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 ++抱怨在constexpr重新声明Foo::f不同。

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

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

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

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

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

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

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

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

如果函数或函数模板的任何声明都有constexpr规范,则其所有声明都应包含constexpr规范。

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

理查德史密斯答案的更新,现在尝试3编译GCC 4.9和5.1,以及叮叮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;
                ^~~~~~~~~~~~~~~~~~~~~

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM