如果函数在类范围内声明,则 constexpr 不起作用

2021-12-31 00:00:00 compiler-errors g++ c++ c++11 constexpr

我使用的是 g++4.8.0,它不包含早期的 constexpr 错误.因此下面的代码工作罚款:

I am using g++4.8.0, which doesn't contain earlier constexpr bug. Thus below code works fine:

constexpr int size() { return 5; }
int array[size()];

int main () {}

但是,如果我将 class 中的变量都作为 static 括起来,那么它会给出 编译器错误:

However, if I enclose both the variable inside a class as static, then it gives compiler error:

struct X {
  constexpr static int size() { return 5; }
  static const int array[size()]; 
};

int main () {}

这里是错误:

错误:数组‘array’的大小不是整数常量表达式

error: size of array ‘array’ is not an integral constant-expression

是否禁止以这种方式使用 constexpr 或另一个 g++ 错误?

Is it forbidden to use constexpr in such a way or yet another g++ bug?

推荐答案

是的,格式不正确.原因如下:

Yes, it is ill-formed. Here's why:

constexpr 函数在用于常量表达式之前需要定义(不仅仅是声明).

A constexpr function needs to be defined (not just declared) before being used in a constant expression.

例如:

constexpr int f(); // declare f
constexpr int x = f(); // use f - ILLEGAL, f not defined
constexpr int f() { return 5; } // define f, too late

类说明符内的函数定义(以及初始值设定项和默认参数)基本上按照它们在类外定义的顺序进行解析.

function definitions inside a class specifier (as well as initializers and default parameters) are essentially parsed in an order like they were defined outside the class.

所以:

struct X {
  constexpr static int size() { return 5; }
  static const int array[size()]; 
};

按以下顺序解析:

struct X {
   constexpr inline static int size(); // function body defered
   static const int array[size()];  // <--- POINT A
};

constexpr inline int X::size() { return 5; }

也就是说,函数体的解析被推迟到类说明符之后.

That is, parsing of function bodies are defered until after the class specifier.

推迟函数体解析的目的是为了让函数体可以转发引用当时尚未声明的类成员,并且它们可以将自己的类用作完整类型:

The purpose of this deferral of function body parsing is so that function bodies can forward reference class members not yet declared at that point, and also so they can use their own class as a complete type:

struct X
{
    void f() { T t; /* OK */ }
    typedef int T;
};

与在命名空间范围内相比:

Compared to at namespace scope:

void f() { T t; /* error, T not declared */ }
typedef int T;

POINT A,编译器还没有size()的定义,所以不能调用.对于编译时性能 constexpr 函数需要在编译期间被调用之前在翻译单元中使用之前定义,否则编译器将不得不进行多次传递以链接"常量表达式评价.

At POINT A, the compiler doesn't have the definition of size() yet, so it can't call it. For compile-time performance constexpr functions need to be defined ahead of their use in the translation unit before being called during compile, otherwise the compiler would have to make a multiple passes just to "link" constant expressions for evaluation.

相关文章