在构造函数中使用 constexpr 成员

Using constexpr member in constructor

我有以下代码:

struct C {
    int var = 3;
};

当我这样使用它时:

constexpr C c;
static_assert(c.var == 3, "");

一切正常,但是如果我想在 constexpr 构造函数中执行此断言,它会失败:

struct C {
    constexpr C() { static_assert(var == 3, ""); }
    int var = 3;
};

为什么会这样? 在 constexpr 构造函数中,每个变量都应该在编译时知道,对吗?

In constexpr constructor every variable should be known at compile time, right?

错了。

A constexpr 构造函数是一个函数(方法),可以在编译时执行(在你的情况下,声明 c constexpr),但也可以在 运行 时执行(例如,声明 C c2; 而不是 constexpr)。

所以构造函数里面的static_assert()是错误的,因为编译器在执行构造函数的时候检查不到运行-time.

也就是说…… 当你按如下方式使用时

constexpr C c;
static_assert(c.var == 3, "");

可以编译,因为 c 被声明为 constexpr,所以 c.var 的值在编译时已知。

但是

C c2;
static_assert(c2.var == 3, "");

给出错误,因为 c2.var 的值不知道编译时间。

写作

constexpr C() { static_assert(var == 3, ""); }

要求在两种情况下都执行 static_assert()

constexpr-函数,无论是构造函数、(静态)成员函数还是自由函数,都是可以在假定适当参数的情况下在编译时求值的函数。

不保证任何特定调用都会在编译时求值,除非它是在需要编译时常量的上下文中完成的。
因此,您不能在需要编译时常量表达式的地方使用任何非 static constexpr 成员。

即使是 GCC 的 __builtin_constant_p(),它允许您有更多的回旋余地,但出于某种原因却无济于事:

http://coliru.stacked-crooked.com/a/2aab3b90335b9d04