嵌套结构尽管与全局结构完全相同但仍会破坏constexpr

Pub*_*bby 18 c++ constexpr c++11

我遇到以下代码时遇到问题:

template<typename T>
constexpr int get(T vec) {
  return vec.get();
}

struct coord {
  constexpr int get() const { return x; }
  int x;
};

struct foo {
    struct coord2 {
      constexpr int get() const { return x; }
      int x;
    };
    constexpr static coord f = { 5 };
    constexpr static int g = get(f); // works

    constexpr static coord2 h = { 5 };
    constexpr static int i = get(h); // doesn't work
};

constexpr coord foo::f;
constexpr foo::coord2 foo::h;

int main(){}
Run Code Online (Sandbox Code Playgroud)

基本上,get(f)被认为是一个常量表达式,但get(h)事实并非如此.唯一改变的是一个使用全局结构coord,而另一个使用嵌套结构coord2.结构的身体是相同的.

为什么是这样?


GCC错误:

test.cpp:20:35: error: field initializer is not constant
Run Code Online (Sandbox Code Playgroud)

Clang错误:

test.cpp:20:26: error: constexpr variable 'i' must be initialized by a constant expression
    constexpr static int i = get(h); // doesn't work
                         ^   ~~~~~~
test.cpp:8:10: note: undefined function 'get' cannot be used in a constant expression
  return vec.get();
         ^
test.cpp:20:30: note: in call to 'get({5})'
    constexpr static int i = get(h); // doesn't work
                             ^
test.cpp:13:21: note: declared here
      constexpr int get() const { return x; }
Run Code Online (Sandbox Code Playgroud)

Ben*_*igt 17

这是一个不变的表达......最终,正如这表明你可以通过i进入main():

错误消息非常清楚发生了什么,这是foo::coord2::get()尚未定义的,因为成员函数定义被延迟到封闭类的末尾,以便它们可以使用稍后声明的成员.

有点令人惊讶的是,定义被推迟到最外层封闭类的末尾,但如果foo::coord2::get()无法访问,你会更加惊讶foo::g.

标准同意编译器,顺便说一句.第9.2p2节的一部分说

在类成员规范中,对于非静态数据成员(包括嵌套类中的此类事物),该类在函数体,缺省参数,异常规范大括号或大小写初始化中被视为完整.

不幸的是,它只是推断出类声明的右括号成为这些延迟区域的定义点.我认为这是标准中的一个缺陷,它没有明确说明这一点.

也可以看看: