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

时间:2014-01-10 19:06:47

标签: c++ c++11 overloading rvalue-reference qualifiers

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建议将标准库中的大多数赋值运算符限制为左值目标(即,将“&”引用限定符添加到赋值运算符),但是this was rejected。所以这是一个潜在的用例,委员会决定不再使用它。那么,再一次,什么是合理的用例?

4 个答案:

答案 0 :(得分:17)

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

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());

编辑:我找到了original proposal paper,它提供了三个激励性的例子:

  1. operator =约束到左值(TemplateRex的答案)
  2. 为成员启用移动(基本上是这个答案)
  3. operator &约束到左值。我认为,当“指针”最终被取消引用时,确保“指针”更有可能存活是明智的:
  4. struct S {
      T operator &() &;
    };
    
    int main() {
      S foo;
      auto p1 = &foo;  // Ok
      auto p2 = &S();  // Error
    }
    

    不能说我曾经亲自使用operator&超载。

答案 1 :(得分:13)

一个用例是prohibit assignment to temporaries

 // 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

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

评论中@dyp的链接还提供了有关使用其他(&&)重载的扩展讨论,如果您想分配给(左值或左值),这可能很有用rvalue)参考。

答案 2 :(得分:3)

如果f()需要一个Foo temp作为此副本并进行修改,则可以改为修改临时this,否则

答案 3 :(得分:0)

一方面,你可以使用它们来防止在语义上无意义的函数被调用临时数据,例如operator=或改变内部状态并返回void的函数,通过添加{ {1}}作为参考限定符。

另一方面,您可以使用它进行优化,例如当您有右值引用时将成员移出对象作为返回值,例如函数&可以返回{{1} }或getName取决于引用限定符。

另一个用例可能是返回对原始对象的引用的运算符和函数,例如std::string const&,它可以专门用于返回右值引用,使结果可移动,这也将是一个优化。 / p>

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