常量和引用成员函数限定符

4
假设我们有一个包含以下两个成员函数的成员类:
class SomeClass
{
private:
  int val = {};
public:

  const int getVarLRef() & {
    return val;
  }
  const int getVarCLRef() const& {
    return val;
  }
};

int main()
{
  auto var1 = SomeClass().getVarCLRef();
  auto var2 = SomeClass().getVarLRef();
  return 0;
}

我不太明白const&&之间有什么区别。如果我们将getVarCLRef函数指定为const&,那么它为什么可以与之一起工作?难道不能只用lvalues调用它吗?

另一方面,getVarLRef却工作得很好,并且在这种情况下如预期地无法编译。

我使用的是C++11和gcc 7.3.0


1
请注意,你例子中的 auto 翻译成 int 而不是 int&。如果你想让它成为引用类型,你应该使用 auto& - Denis Sheremet
有趣的观察。我猜 https://dev59.com/ymAg5IYBdhLWcg3w7erx 和 https://dev59.com/tmEh5IYBdhLWcg3w7XPt 的答案并不是完全正确的(大部分回答提到了 & 要求对象是一个左值)... - Max Langhof
顺便提一下:通过const值返回是毫无意义的,因为该值将被复制(即使发生复制省略也不会改变任何内容),这只会使代码更难阅读。在最坏的情况下,您只是防止直接使用对象(x.get().foo();),但仍然可以几乎总是(自C++17以来;由于保证复制省略)通过auto y = x.get(); y.foo();绕过。 - Aconcagua
2个回答

2

它难道不应该只被左值调用吗?

因为右值也可以绑定到对const的左值引用上。就像下面的代码一样。

const SomeClass& r = SomeClass();

另一方面,rvalue 无法绑定到非 const 的 lvalue 引用上,因此调用 getVarLRef 将会失败,正如您所预期的那样。

@toozyfuzzy 我不确定你的意思是什么... 理论上它与 const int getVarCLRef(const SomeClass&); getVarCLRef(SomeClass{}); 相同;即将一个 rvalue 传递给接受 lvalue-reference to const 的函数。 - songyuanyao
@songyuanyao 在问题中,'const&' 在成员函数定义中是什么意思?当一个人像那样定义成员函数时,期望的结果是什么? - toozyfuzzy
2
@toozyfuzzy 我想不出其他的了。使用&&&来提供重载成员函数似乎更自然一些。 - songyuanyao
1
@toozyfuzzy 在你的具体情况下,看起来你根本不需要那些限定符,只需使用 const 或什么都不用。这样,在常量对象上将选择 const 版本,而在可变对象上将选择另一个版本。使用 & 和 && 限定符会有所区别:你将在左值引用还是右值引用上调用该函数?也许你的类可能希望表现得不同? - Aconcagua
1
假设您的函数返回一些内部缓冲区,例如 std::string。使用左值引用,您的函数可能会返回一个副本。使用右值引用,函数可能会假定您不再需要该对象,并且它可能会将内部字符串的内容移动到返回值中,从而避免更昂贵的复制操作。 - Aconcagua
显示剩余4条评论

2

常量和引用成员函数限定符是为了能够像普通参数一样将这些限定符应用于 "this",因此主要有以下内容:

int getVarLRef(SomeClass& self) { return self.val; }
int getVarCLRef(const SomeClass& self) { return self.val; }

我想你已经知道:

getVarCLRef(SomeClass()); // Valid, temporary can bind to const lvalue reference
getVarLRef(SomeClass()); // INVALID, temporary CANNOT bind to non-const lvalue reference

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