为什么常量双 &&&不适用于左值引用?

Why const double && doesn't work for lvalue reference?

本文关键字:引用 不适用 常量 为什么 适用于      更新时间:2023-10-16

请解释一下它是如何工作的? 为什么双&&适用于左值和右值? 为什么常量双&不为左值工作?

template <typename U>
void function(U& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(var1);
function(45); //error
}

错误:从类型为"int"函数 (45) 的右值初始化类型为"int&"的非常量引用无效;////////////////////////////////////////////////

template <typename U>
void function(const U& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(var1);
function(45);
}

///

template <typename U>
void function(U&& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(var1);
function(45);
}

///

template <typename U>
void function(const U&& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(var1);  // error
function(45);
}

错误:无法将"int"左值绑定到"const int&&"函数(var1);

double &&

不适用于左值。但是,您的代码中没有double &&,您必须为推导UU &&。这是所谓的转发引用的特殊语法。

C++模板推导规则中有一个特殊的规则,它说当参数类型为T&&时,其中T是推导类型,并且参数是类型X的左值,则使用X&而不是X进行类型推导。

在你的例子中,这意味着U被推导出为int&,所以参数的类型var从"int& &&"折叠到int &

您可以通过搜索"转发引用"(历史上称为"通用引用")或"完美转发"等术语来了解有关此机制的更多信息。

让我们先总结一下规则。

左值
  1. 可以绑定到左值引用
  2. 左值不能绑定到右值引用
  3. 右值可以绑定到常量值的左值引用
  4. 右值不能绑定到非常量值的左值引用
  5. 右值
  6. 可以绑定到右值引用
  7. 左值可以绑定到转发引用(并保留其值类别)
  8. 右值可以绑定到转发引用(并保留其值类别)

第一种情况是对非常量的正确引用,然后

function(var1); // rule#1 -> fine
function(45);   // rule#4 -> fail

第二种情况是常量,然后

function(var1); // rule#1 -> fine
function(45);   // rule#3 -> fine

第三种情况是转发引用,然后

function(var1); // rule#6 -> fine
function(45);   // rule#7 -> fine

第四种情况是右值引用,然后

function(var1); // rule#2 -> fail
function(45);   // rule#5 -> fine

值得注意的是右值引用和转发引用之间的区别:

(强调我的)

声明为对同一函数模板的 CV非限定类型模板参数的 rvalue 引用的函数模板的函数参数

在您的示例中,function(var1)将推断var1用法为lvalue。要使其与基于 rvalue 的模板兼容,您必须对您的编译器有所帮助:

template <typename U>
void function(const U&& var) {
std::cout << var << std::endl;
}
int main()
{
int var1 = 45;
function(std::move(var1));  // let convert lvalue to rvalue
function(45);
}

附言是的,你应该总是问自己"我真的需要那个右值参考,还是我对那个旧的好左值参考完全没问题?