在C++中众所周知,初始化引用时,类型必须匹配。所以下面的代码片段会导致错误(全局范围内,下同):
unsigned i;
int & p = i; // error
但是对 const 的引用有一个例外,因此以下在允许类型转换的情况下是正确的:
unsigned i;
const int & p = i; // ok
但是如果我将
p
定义为constexpr
,就会出现编译错误:
unsigned i;
constexpr const int & p = i; // error: the value of 'i' is not usable in a constant expression
错误消息说
i
不是 const,我认为这是无关紧要的,因为如果我将类型从有符号更改为无符号,即没有类型转换,则不会出现编译错误:
unsigned i;
constexpr const unsigned & p = i;
const
这里可以省略。
所以,看来是类型转换导致了
中的编译错误unsigned i;
constexpr const int & p = i; // error
但我不确定。你能告诉我什么 C++ 标准规则导致了这个错误吗?我在 C++20 下在 GCC 和 MSVC 中测试了上述代码。
这部分:
unsigned i;
int& p = i;
..无法编译,因为它需要将左值引用绑定到将
unsigned
转换为 int
时具体化的临时值。详情可以参考dcl.init.ref#5.2:
否则,如果引用是对非 const 限定或 volatile 限定的类型的左值引用,则程序格式错误。
同时,C++ 允许将
const
引用绑定到这样的临时对象,因此这可以正常工作:
unsigned i;
const int& p = i;
这部分内容由 dcl.init.ref#5.4.2:
涵盖否则,初始化表达式将隐式转换为
类型的纯右值。应用临时物化转换,考虑纯右值的类型为T1
,并且引用绑定到结果。cv1 T1
但是,当使用
constexpr
时,您应该提供一个常量表达式,在这种情况下不满足:
unsigned i;
constexpr const int& p = i;
如果在常量表达式中使用引用,则应按照 expr.const#14:
直接绑定它们类型的转换常量表达式是一个表达式,隐式转换为T
类型,其中转换后的表达式是常量表达式,隐式转换序列仅包含T
...
以及引用绑定(如果有)直接绑定的位置。
当发生隐式转换时,无法进行直接限制,如 dcl.init.ref#5:
在除最后一种情况之外的所有情况下(即,将初始化表达式隐式转换为引用类型),引用被称为直接绑定到初始化表达式。
但是将常量表达式引用绑定到非临时全局变量仍然可以,因为它不涉及任何临时变量,所以编译得很好:
unsigned i;
constexpr const unsigned& p = i;