【问题标题】:Invalid initialization of non-const reference of type类型的非常量引用的无效初始化
【发布时间】:2015-01-26 03:09:36
【问题描述】:

在以下代码中,我无法将临时对象作为参数传递给 printAge 函数:

struct Person {
  int age;
  Person(int _age): age(_age) {}
};

void printAge(Person &person) {
   cout << "Age: " << person.age << endl;
}

int main () {
  Person p(50);
  printAge(Person(50));  // fails!
  printAge(p);
  return 0;
}

我得到的错误是:

error: invalid initialization of non-const reference of type ‘Person&’ from an rvalue of type ‘Person’

我意识到这与将 lValue 传递给期望 rValue 的函数有关...有没有办法通过使用 std::move 或其他方法将我的 lValue 转换为 rValue?我尝试采用一个常量参数,但这似乎不起作用。

【问题讨论】:

  • 情况正好相反。您正在将右值传递给需要左值的函数。非 const 左值引用不能绑定到右值,但您可以改用 const 左值引用。
  • “我尝试采用一个常量参数,但这似乎确实有效。”所以你解决了这个问题,但决定放弃这个解决方案,因为它似乎有效?
  • 糟糕,我留下了一个不是!

标签: c++ pass-by-reference lvalue-to-rvalue


【解决方案1】:

只需让您的打印函数通过const&amp; 获取您的参数。这在逻辑上也是正确的,因为它不会修改您的论点。

void printAge(const Person &person) {
   cout << "Age: " << person.age << endl;
}

实际的问题是相反的。您正在将临时(右值)传递给需要左值的函数。

【讨论】:

    【解决方案2】:

    或者,如果你有一个 C++11 兼容的编译器,可以使用所谓的通用引用方法,通过引用折叠规则,可以绑定到左值和右值引用:

    #include <iostream>
    using namespace std;
    
    struct Person {
      int age;
      Person(int _age): age(_age) {}
    };
    
    template<typename T> // can bind to both lvalue AND rvalue references
    void printAge(T&& person) {
       cout << "Age: " << person.age << endl;
    }
    
    int main () {
      Person p(50);
      printAge(Person(50));  // works now
      printAge(p);
      return 0;
    }
    

    或者,在 C++14 中,

    void printAge(auto&& person) {
       cout << "Age: " << person.age << endl;
    }
    

    【讨论】:

    • 这不是 urefs 的用途。如果您想要一个变量的只读视图,您只需通过const&amp; 获取它。
    • @bamboon 你能扩展一下吗?没有真正理解你的评论。你是说urefs只是为了完美转发?不过,urefs 在这里工作得很好。好的,看到你更新的评论,同意。
    • 是的,基本上。虽然我不认为这真的是错误的,但我认为这让问题变得非常复杂,以及为什么没有人知道如何正确传递变量的原因(例如:参见 Herb Sutter 在 cppcon 的演讲)。编辑:啊,是的,我第一次输入的速度太快了。
    • @bamboon 正确 :) 我不会这么沮丧,因为没有人知道如何通过 const 引用传递 :) 我写的解决方案没有真正考虑名称 printAge,因为也可以有一个叫做modifyAge 的东西。但同样,我同意,在了解 auto&amp;&amp; x 的真正含义以及参考折叠规则是什么之前,首先应该知道 const type&amp; x 是什么。你能发个 Herb 演讲的链接吗?
    • @bamboon 这也是为什么我认为现在“通用参考”被“转发参考”取代的原因,尽管我对此不是 100% 确定的。无论如何,很好的评论。
    【解决方案3】:

    如果您运行 g++ 或 gcc 编译器,您的代码将无法工作。您需要将const 添加到void printAge(const Person &amp;person)。但是,在 Visual Studio 中它可以正常工作。我已经针对 VS2010 和 VS2012 进行了测试,并且在以下两个代码中都可以正常工作。

     #include<iostream>
    
    using namespace std;
    struct Person {
      int age;
      Person(int _age): age(_age) {}
    };
    
    void printAge(Person &person) {
       cout << "Age: " << person.age << endl;
    }
    
    int main () {
      Person p(50);
      printAge(Person(50));  // DOES NOT fail!
      printAge(p);
      return 0;
    }
    

    【讨论】:

    • 不,这不应该编译。这一定又是某个 MSVC 扩展。
    • 是的,我刚刚签入了 g++ 或 gcc;他们都没有编译它;但是在 VS 中,将对象作为参数传递是很正常的,尽管它没有定义为 const;不过应该避免。
    • 你可以避免它,但对于 VS 用户来说,使用它没关系。
    • 我是 VS 用户,有时需要将我的代码提供给不知道 C++ 编译器的人。
    • 如果你想编写可移植代码(而不是只为 Windows 编译),即使你使用 VS 你也应该使用标准 C++
    猜你喜欢
    • 2013-01-07
    • 2013-10-11
    • 1970-01-01
    • 2013-09-04
    • 2020-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多