为什么从 '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
。
我有这个简单的例子:
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
。