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

ndk*_*pel 38 c++ constexpr c++11

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

尝试1:

struct Foo {
    constexpr Foo() {}
    static constexpr Foo f = Foo();
};
constexpr Foo Foo::f;
Run Code Online (Sandbox Code Playgroud)

g ++ 4.7.0说:'无效使用不完整类型'指的是Foo()调用.

尝试2:

struct Foo {
    constexpr Foo() {}
    static constexpr Foo f;
};
constexpr Foo Foo::f = Foo();
Run Code Online (Sandbox Code Playgroud)

现在的问题是在类定义中缺少constexpr成员的初始化器f.

尝试3:

struct Foo {
    constexpr Foo() {}
    static const Foo f;
};
constexpr Foo Foo::f = Foo();
Run Code Online (Sandbox Code Playgroud)

现在g ++抱怨重新声明Foo::f不同的内容constexpr.

jog*_*pan 32

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

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

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

struct Foo {
  constexpr Foo() {}
  static constexpr Foo f {};
};
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • +1让我们了解当前的讨论状态以及产生答案! (2认同)
  • 我只是遇到了这个确切的问题。似乎与“静态const”如何与不完整类型一起使用不一致。我想我现在只需要处理一个“静态const”! (2认同)

Ric*_*ith 11

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

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

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


xav*_*urs 8

理查德史密斯答案的更新,现在尝试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;
Run Code Online (Sandbox Code Playgroud)

但是,当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
Run Code Online (Sandbox Code Playgroud)

Clang错误:

error: non-type template argument is not a constant expression
std::array<int, Foo<std::size_t>::f.v> a;
                ^~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,如果将定义放入.h文件中,则在链接时最终会出现“多个定义”错误。而且,如果将其放在C ++文件中,其他C ++文件也不知道它是constexpr。 (2认同)
  • @monkey0506 我遇到了类似的问题。您能否展示如何使用 C++17 内联变量来执行此操作? (2认同)