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

Kno*_*abe 24 c++ overloading qualifiers rvalue-reference c++11

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
Run Code Online (Sandbox Code Playgroud)

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

我看到N2819建议将标准库中的大多数赋值运算符限制为左值目标(即向赋值运算符添加" &"引用限定符),但这被拒绝了.所以这是一个潜在的用例,委员会决定不再使用它.那么,再一次,什么是合理的用例?

Cas*_*sey 18

在提供reference-getters的类中,ref-qualifier重载可以在从rvalue中提取时激活移动语义.例如:

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();
Run Code Online (Sandbox Code Playgroud)

这似乎需要付出很多努力才能获得更短的语法

auto hhc = factory().get();
Run Code Online (Sandbox Code Playgroud)

有同样的效果

auto hhc = std::move(factory().get());
Run Code Online (Sandbox Code Playgroud)

编辑:我找到了原始的提案文件,它提供了三个激励性的例子:

  1. 约束operator =左值(TemplateRex的答案)
  2. 为成员启用移动(基本上这个答案)
  3. 限制operator &左值.我认为,当"指针"最终被取消引用时,确保"指针"更可能存活是明智的:
struct S {
  T operator &() &;
};

int main() {
  S foo;
  auto p1 = &foo;  // Ok
  auto p2 = &S();  // Error
}
Run Code Online (Sandbox Code Playgroud)

不能说我曾经亲自使用operator&过载.


Tem*_*Rex 13

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

 // 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; }
Run Code Online (Sandbox Code Playgroud)

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

       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
Run Code Online (Sandbox Code Playgroud)

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

注释中@dyp的链接还提供了有关使用other(&&)重载的扩展讨论,如果要分配(左值或右值)引用,这可能很有用.