为什么右值引用模板变量
b<int>
能够绑定到左值a
?
#include <iostream>
int a = 3;
template<typename T>
T&& b = a;
int main() {
if(std::is_same_v<decltype(b<int>), int&&>) {
std::cout << "same\n";
} else {
std::cout << "different\n";
}
}
Output: same
为什么右值引用模板变量
能够绑定到左值b<int>
?a
本题假设错误。右值引用
b<int>
无法绑定到 a
。通过您的实施,没有错误,因为decltype(b<int>)
本身不会导致b<int>
的实例化。
这是否可以有点不清楚。对应引用自C++17草案标准如下[temp.inst/6]:
除非变量模板特化已被显式实例化或显式特化,否则变量模板特化在使用特化时隐式实例化.
According to this quote,我认为应该实例化
b
,因为使用了b<int>
(即使在未评估的上下文中)。
不过现在的草案,措辞不一样了[temp.inst/7/1]:
除非变量模板特化是声明的特化,否则当变量模板特化在需要变量定义存在的上下文中被引用时,或者定义的存在影响程序的语义时,隐式实例化。
无论如何,一旦你确定实例是必需的,你就会得到一个编译错误。
我想从评论和大牛的回答中总结集体智慧
在模板上下文中,
T&&
并不意味着r值引用而是转发引用(也称为通用引用)。将其视为以下替代(Godbolt 证明):
T = int ==> T&& type is int&&
T = int& ==> T&& type is int&
T = int&& ==> T&& type is int&&
因此,在您的代码中:
template<typename T>
T&& b = a;
// On different instantiations this generates:
int&& b<int> = a; // error, can't bind rvalue reference to lvalue
int& b<int&> = a; // ok
int&& b<int&&> = a; // error, can't bind rvalue reference to lvalue
因此,只有
b<int&>
会编译(演示 Godbolt)。
decltype(b<int>)
恰好通过编译的原因是 decltype
运算符 仅检查声明是否格式正确 但不进行任何实例化,因此 不验证定义是否格式正确。有关基于 C++ 标准措辞的更深入解释,请参阅 Daniel 的回答。