18

我在使用以下代码时遇到问题:

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(){}

本质上,get(f)被认为是一个常量表达式,但get(h)不是。唯一改变的是一个使用全局结构coord,而另一个使用嵌套结构coord2。结构的主体是相同的。

为什么是这样?


海合会错误:

test.cpp:20:35: error: field initializer is not constant

叮当错误:

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; }
4

1 回答 1

17

这是一个常量表达式....最终,正如您可以看到的那样,您可以通过以下方式i看到main()

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

定义延迟到最外面的封闭类结束时,这有点令人惊讶,但如果foo::coord2::get()无法访问foo::g.

该标准与编译器一致,顺便说一句。第 9.2p2 节的一部分说

在类成员规范中,类在函数体、默认参数、异常规范和非静态数据成员(包括嵌套类中的此类内容)的大括号或等式初始化器中被视为完整。

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

也可以看看:

于 2013-05-15T00:47:54.867 回答