[英]Define a static constexpr member of same type of a template class
[英]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.