在引用限定符上重载成员函数的用例是什么?

问题描述 投票:0回答:4

C++11 使得基于引用限定符重载成员函数成为可能:

class Foo {
public:
  void f() &;   // for when *this is an lvalue
  void f() &&;  // for when *this is an rvalue
};

Foo obj;
obj.f();               // calls lvalue overload
std::move(obj).f();    // calls rvalue overload

我了解这是如何工作的,但它的用例是什么?

我看到N2819建议将标准库中的大多数赋值运算符限制为左值目标(即,向赋值运算符添加“

&
”引用限定符),但是这被拒绝了。因此,这是一个潜在的用例,委员会决定不采用它。那么,再一次,什么是合理的用例?

c++ c++11 overloading rvalue-reference qualifiers
4个回答
25
投票

在提供引用获取器的类中,引用限定符重载可以在从右值提取时激活移动语义。例如:

class some_class {
  huge_heavy_class hhc;
public:
  huge_heavy_class& get() & {
    return hhc;
  }
  huge_heavy_class const& get() const& {
    return hhc;
  }
  huge_heavy_class&& get() && {
    return std::move(hhc);
  }
};

some_class factory();
auto hhc = factory().get();

这似乎确实需要投入大量精力才能获得更短的语法

auto hhc = factory().get();

效果相同
auto hhc = std::move(factory().get());

原始提案论文 N1821 提供了三个激励示例:

  1. operator =
    限制为左值(TemplateRex 的答案

  2. 为会员启用移动(此答案)

  3. operator &
    限制为左值。我认为这是明智的,以确保当“指针”最终被取消引用时,“被指向者”更有可能还活着:

     struct S {
       T operator &() &;
     };
    
     int main() {
       S foo;
       auto p1 = &foo;  // Ok
       auto p2 = &S();  // Error
     }
    

不能说我个人曾经使用过

operator&
超载。


14
投票

一个用例是禁止分配给临时人员

 // can only be used with lvalues
 T& operator*=(T const& other) & { /* ... */ return *this; } 

 // not possible to do (a * b) = c;
 T operator*(T const& lhs, T const& rhs) { return lhs *= rhs; }

而不使用参考限定符会让你在两个坏处之间做出选择

       T operator*(T const& lhs, T const& rhs); // can be used on rvalues
 const T operator*(T const& lhs, T const& rhs); // inhibits move semantics

第一个选择允许移动语义,但在用户定义类型上的行为与在内置类型上的行为不同(不像整数那样)。第二种选择将停止分配但消除移动语义(例如矩阵乘法可能会影响性能)。

评论中 @dyp 的链接还提供了有关使用其他 (

&&
) 重载的扩展讨论,如果您想分配给(左值或右值)引用,这会很有用。


3
投票

如果 f() 需要一个 Foo temp ,它是它的副本并进行了修改,您可以修改该 temp

this
,否则您不能


0
投票

一方面,您可以通过添加

operator=
作为引用限定符,使用它们来防止调用在语义上无意义的临时函数,例如
void
或改变内部状态并返回
&
的函数.

另一方面,您可以使用它进行优化,例如当您有右值引用时将成员移出对象作为返回值,例如函数

getName
可以返回
std::string const&
std::string&&
,具体取决于关于参考限定符。

另一个用例可能是返回对原始对象的引用的运算符和函数,例如

Foo& operator+=(Foo&)
可以专门返回右值引用,从而使结果可移动,这又是一种优化。

TL;DR:用它来防止函数的错误使用或进行优化。

© www.soinside.com 2019 - 2024. All rights reserved.