为什么 const double && 不适用于左值引用?

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

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

template <typename U>
void function(U& var) {
    std::cout << var << std::endl;
}

int main()
{
    int var1 = 45;
    function(var1);
    function(45); //error
}

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

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 &&。这是 so-called 转发引用的特殊语法。

C++模板推导规则中有一个特殊的规则,当参数类型为T&&时,其中T是推导类型,参数是[=16=类型的左值], 然后使用 X& 代替 X 进行类型推导。

在您的例子中,这意味着 U 被推断为 int&,因此参数类型 var 从“int& &&”折叠为 int &.

您可以通过搜索 "forwarding reference"(历史上称为 "universal reference")或 "perfect forwarding."

等术语来了解有关此机制的更多信息

先总结一下规则。

  1. 左值可以绑定到 lvalue-reference
  2. 左值不能绑定到 rvalue-reference
  3. rvalues 可以绑定到 lvalue-reference 到 const
  4. 右值不能绑定到 lvalue-reference 到 non-const
  5. 右值可以绑定到 rvalue-reference
  6. 左值可以绑定到 forwarding-reference(并保留其值类别)
  7. 右值可以绑定到 forwarding-reference(并保留其值类别)

第一种情况是lvalue-reference到non-const,那么

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

第二种情况是lvalue-reference转const,然后

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

第3种情况是forwarding-reference,那么

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

第4种情况是rvalue-reference,那么

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

值得注意的是rvalue-reference和forwarding-reference的区别:

(强调我的)

function parameter of a function template declared as rvalue reference to cv-unqualified type template parameter of that same function template

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

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);
}

P.S。是的,你应该经常问自己 "do I really need that rvalue reference, or I'm perfectly fine with that old good lvalue ref?"