25

我正在使用 g++4.8.0,它不包含早期的constexpr错误。因此下面的代码工作正常

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

int main () {}

但是,如果我将两个变量都包含在 a classas 中static,则会出现编译器错误

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

int main () {}

这是错误:

错误:数组“数组”的大小不是整数常量表达式

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

4

3 回答 3

32

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

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

例如:

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

类说明符内的函数定义(以及初始化程序和默认参数)本质上是按照它们在类外定义的顺序进行解析的。

所以这:

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

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

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

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

与命名空间范围相比:

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

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

于 2013-05-11T04:48:01.050 回答
6

显然它甚至不是一个 bug,因为它的状态是RESOLVED INVALID,这意味着 GCC 和那个 bugzilla 背后的人,在审查了这个问题之后,不要认为这是一个 GCC bug。

我在该页面上提醒您,因为在其中一个相关帖子中也有此行为的答案。

于 2013-05-11T04:38:31.447 回答
2

我只是想补充一点,尽管这可能不是一个好的做法,并且会限制您在其声明的同一编译单元中定义类主体,但可以强制编译器在同一点编译函数主体的定义通过添加冗余模板参数作为其声明:

template <typename = void>
struct X {
   constexpr static int size() { return 5; }
   static const int array[size()]; 
};

int main()
{
    X<> x{};
    ...
}
于 2018-08-29T12:58:13.693 回答