我对
constexpr
的概念感到非常困惑,因为我读过 constexpr
是在编译时评估的,因此与正常的 const
相比,它对于性能优化很有用。
constexpr int i = 0;
constexpr int& ri = i;
上面的代码返回错误“来自'const int'类型的表达式的'int&'类型的引用无效初始化”,为什么?
另外,接下来的代码有一个错误:
constexpr int i = 0;
constexpr int* ri = &i;
如果我将
constexpr
关键字替换为 const
,以上所有内容都可以正常工作。
constexpr int i = 0;
constexpr int * ri = &i;
第二行是一个问题,因为指针没有指向
const
对象。指针本身是 const
。
使用
constexpr int i = 0;
constexpr int const * ri = &i;
解决了这个问题。但是,如果变量是在函数作用域中定义的,这仍然是一个问题。
constexpr int i = 0;
constexpr int const* ri = &i;
int main() {}
是一个有效的程序。
void foo()
{
constexpr int i = 0;
constexpr int const* ri = &i;
}
int main() {}
不是有效的程序。
以下是 C++11 标准关于 地址常量表达式 的规定:
5.19 常量表达式
3.. 地址常量表达式是指针类型的纯右值核心常量表达式,其计算结果为具有静态存储持续时间的对象的地址、函数的地址或空指针值,或者类型的纯右值核心常量表达式
。std::nullptr_t
回复
” 如果我用 const 替换 constexpr 单词,以上所有操作都可以正常工作。”
A
const int*
本质上意味着 (const int)*
,只不过你不能那样使用括号。 A constexpr int*
表示 constepxr (int*)
(同上)。
这是因为
constexpr
不是类型的一部分,你不能将类型命名为 constexpr int
,而 const
是类型的一部分。
而不是
constexpr int i = 0;
constexpr int& ri = i;
试图声明对非
constexpr
的const
引用,只需写
constexpr int i = 0;
constexpr int const& ri = i;
您可以向后阅读,因为
ri
是对 const
int
的引用,即 constexpr
(在编译时评估)。
附录:
似乎 C++14 要求本地非
static
constexpr
对象具有 自动存储持续时间,以 as-if 规则为模进行优化。
为了满足这一点,即使代码可以跨编译器移植,如果上述声明出现在函数本地,请添加
static
以确保引用的对象的静态存储持续时间:
void oops()
{
static constexpr int i = 0; // Necessary with some compilers.
constexpr int const& ri = i;
}
否则它可能无法编译,例如g++,并且通过省略对 constexpr
的适当约束,这“可能”是 C++14 和 C++11 标准所要求的。
constexpr
是在
编译时评估的。所以编译时该值必须是可评估的。 例如:
constexpr int i = 0;
constexpr int& ri = i;
第一行,编译时可评估0,其值为0。
但是对于第二行,编译器需要
i
的地址来进行赋值,这是在运行时确定的。所以这条线会失败。
constexpr
功能定义了编译期间发生的计算。合理的问题:
允许
constexpr
代码中使用相当有限的功能。有人可能会争论为什么是这个集合而不是其他东西?好吧,稍后标准可能会发展并允许更多。