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

C++ 什么';在引用限定符上重载成员函数的用例是什么?,c++,c++11,overloading,rvalue-reference,qualifiers,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 ov

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
我理解这是如何工作的,但它的用例是什么

我看到有人提议将标准库中的大多数赋值运算符限制为左值目标(即,向赋值运算符添加“
&
”引用限定符),但是。所以这是一个潜在的用例,委员会决定不使用它。那么,什么是合理的用例呢?

一个用例是

然而,不使用引用限定符会让您在两个坏选项之间进行选择

       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
第一个选项允许移动语义,但在用户定义类型上的行为与在内置类型上的行为不同(与ints不同)。第二种选择将停止分配,但消除移动语义(例如矩阵乘法可能会影响性能)


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

如果f()需要一个作为其副本并经过修改的Foo-temp,在提供引用getter的类中,可以修改temp
this
,而在提供引用getter的类中,ref限定符重载可以在从右值提取时激活移动语义。例如:

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());
编辑:我找到了,它提供了三个激励示例:

  • 运算符=
    约束为左值(TemplateRex的答案)
  • 为成员启用移动(基本上就是这个答案)
  • 运算符&
    约束为左值。我认为,当“指针”最终被解除引用时,确保“指针对象”更有可能处于活动状态是明智的:

  • 不能说我个人曾经使用过
    操作符&
    重载。

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

    另一方面,您可以使用它进行优化,例如当您有一个右值引用时,将一个成员作为返回值移出对象,例如,函数
    getName
    可以根据引用限定符返回
    std::string const&
    std::string&

    另一个用例可能是返回对原始对象的引用的操作符和函数,例如
    Foo&operator+=(Foo&)
    ,可以专门化为返回右值引用,从而使结果可移动,这同样是一种优化


    TL;DR:用它来防止函数的不正确使用或优化。

    更一般地说:防止公开指向临时文件内部数据的引用或指针。你什么时候希望它们是可分配的?@Mehrdad我不知道,但是如果你不指定
    &
    ,它们会很有趣。@TemplateRex:interest。我觉得这可以通过完全禁止通过
    =rhs
    分配右值来解决,而不是引入这个更一般的构造。如果人们真的想给右值赋值,他们可以只做
    。operator=(rhs)
    。@Mehrdad这可能不会让编译器编写者的生活变得复杂,这并不令人惊讶:-)
    巨重类&&get()&
    是错误的(导致一个悬空引用,应该是
    巨重类get()&
    ),和
    auto hhc=std::move(factory().get())
    将是多余的。@ildjarn为什么您关心的是返回右值引用,而不是返回左值引用?一个不比另一个更容易摇摆。是的,这篇文章的重点是要编写大量代码,以避免需要编写
    std::move(factory().get())
    -我想我需要更清楚地说明这一点。因为左值引用只针对左值返回,因此不成问题……我将此标记为答案,因为它很好地总结了情况,它还链接到原始提案。
    auto hhc = std::move(factory().get());
    
    struct S {
      T operator &() &;
    };
    
    int main() {
      S foo;
      auto p1 = &foo;  // Ok
      auto p2 = &S();  // Error
    }