非 const 引用类型的无效初始化

18
在下面的代码中,我无法将一个临时对象作为参数传递给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左值引用来代替。 - juanchopanza
4
你尝试使用恒定参数,但似乎并没有起作用。所以你解决了问题,但决定放弃这个方案,因为它似乎行不通? - molbdnilo
糟糕,我漏掉了一个“不”! - jeffreyveon
3个回答

18

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

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

实际的问题正好相反。你正在将一个临时值(rvalue)传递给一个期望 lvalue 的函数。


10

或者,如果您有符合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;
}

4
这不是urefs的用途。如果您想要一个变量的只读视图,应该通过 const& 来获取它。 - Stephan Dollberg
@bamboon 正确 :) 我不会如此沮丧地说没有人知道如何通过const引用传递参数 :) 而且我写的解决方案并没有真正考虑到名称printAge,因为也可以有叫做modifyAge的东西。但是再次强调,我同意,应该先了解const type& x是什么,然后再学习auto&& x的含义以及引用折叠规则。你能发一下Herb的演讲链接吗? - vsoftco
@bamboon,这也是我认为现在“通用引用”被“转发引用”取代的原因,虽然我不完全确定。无论如何,评论很好。 - vsoftco
@T.C. 所以我猜除非用于转发,否则不应该使用urefs,对吗? - vsoftco
@vsoftco 抱歉,我的评论应该是针对下面的答案。我错误地将其放在了你的答案中。 - Jagannath
显示剩余8条评论

-2

如果您使用g++或gcc编译器运行代码,它将无法正常工作。您需要在void printAge(const Person &person)中添加const。但是,在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;
}

2
不,这应该无法编译。这肯定又是MSVC的某个扩展功能。 - Stephan Dollberg
是的,我刚刚在g++或gcc中检查了一下;它们都无法编译它;但在VS中,将对象作为参数传递,即使它没有定义为const,也很正常;尽管应该避免这样做。 - telcom
1
你可以避免使用它,但对于VS用户来说使用它是可以的。 - telcom
我是一个VS用户,有时需要将我的代码提供给那些使用未知C++编译器的人。 - Neil Kirk
如果你想编写可移植的代码(而不仅仅是为 Windows 编译),即使你使用 VS,也应该使用标准的 C++。 - vsoftco
MSVC有一个危险的扩展,允许非const左值引用绑定到rvalue。你不应该使用它。 - T.C.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接