为什么从 'constexpr derived' 对象初始化 'const reference to base' 对象不会产生常量表达式?

Why initializing a 'const reference to base' object from 'constexpr derived' object doesn't yields constant expression?

我有这个简单的例子:

struct base
{
   constexpr base () {};
};
   
struct derived: public base
{
    constexpr derived () {};
};
  

int main() 
{
    constexpr derived d{};
    constexpr const base &b = d;  // why error?
}

G++ 给我以下错误:

error: '(const base&)(& d)' is not a constant expression

而且 clang++ 给了我以下错误:

error: constexpr variable 'b' must be initialized by a constant expression.

note: reference to subobject of 'd' is not a constant expression. Add 'static' to give it a constant address.

我很清楚clang给出了解决方案,但我不明白为什么问题解决了?

“对d的子对象的引用不是常量表达式。”,而且这里的子对象有constexpr构造函数所以不是常量表达式?

最后,我不明白为什么使用static可以解决问题?

请在答案中引用标准(如果可能)。

Clang给出的解释是正确的

Constexpr 不会改变变量的存储(它在内存中的位置)。如果你声明一个 non-static constexpr 变量,它仍然会进入堆栈,就像所有其他 non-static 局部变量一样。

int test() {
  constexpr int a = 3; //a gets created here and put on the stack
  const int *b = &a; //Pointer to a location on the stack
} //a gets destroyed when the function ends

这意味着该局部变量的地址可以随着函数的每次调用而改变。在任何给定时间也可以有多个变量副本,即如果多个线程执行函数或函数递归。

总的来说,局部变量的地址永远不能是常量表达式,无论该变量是 const、constexpr、volatile 还是其他任何变量。

static 关键字改变了这一点。它将局部变量“提升”到静态存储中,这意味着它的行为类似于 global 变量,仅在该函数中可见。特别是,变量有一个固定的地址,并且只有一个变量副本,无论函数执行的频率如何(如果有的话)。全局变量的地址是常量表达式。

如果您想要 derived d 的单个全局常量实例,只需按照 Clang 的建议在其前面添加 static