What's a use case for overloading member functions on reference qualifiers?

前端 未结 4 848
天涯浪人
天涯浪人 2020-11-28 08:22

C++11 makes it possible to overload member functions based on reference qualifiers:

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


        
相关标签:
4条回答
  • 2020-11-28 08:35

    One use case is to 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; }
    

    whereas not using the reference qualifier would leave you the choice between two bads

           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
    

    The first choice allows move semantics, but acts differently on user-defined types than on builtins (doesn't do as the ints do). The second choice would stop the assigment but eliminate move semantics (possible performance hit for e.g. matrix multiplication).

    The links by @dyp in the comments also provide an extended discussion on using the other (&&) overload, which can be useful if you want to assign to (either lvalue or rvalue) references.

    0 讨论(0)
  • 2020-11-28 08:42

    If f() needs a Foo temp that is a copy of this and modified, you can modify the temp this instead while you can't otherwise

    0 讨论(0)
  • 2020-11-28 08:44

    On the one hand you can use them to prevent functions that are semantically nonsensical to call on temporaries from being called, such as operator= or functions that mutate internal state and return void, by adding & as a reference qualifier.

    On the other hand you can use it for optimizations such as moving a member out of the object as a return value when you have an rvalue reference, for example a function getName could return either a std::string const& or std::string&& depending on the reference qualifier.

    Another use case might be operators and functions that return a reference to the original object such as Foo& operator+=(Foo&) which could be specialized to return an rvalue reference instead, making the result movable, which would again be an optimization.

    TL;DR: Use it to prevent incorrect usage of a function or for optimization.

    0 讨论(0)
  • 2020-11-28 08:54

    In a class that provides reference-getters, ref-qualifier overloading can activate move semantics when extracting from an 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();
    

    This does seem like a lot of effort to invest only to have the shorter syntax

    auto hhc = factory().get();
    

    have the same effect as

    auto hhc = std::move(factory().get());
    

    EDIT: I found the original proposal paper, it provides three motivating examples:

    1. Constraining operator = to lvalues (TemplateRex's answer)
    2. Enabling move for members (basically this answer)
    3. Constraining operator & to lvalues. I suppose this is sensible to ensure that the "pointee" is more likely to be alive when the "pointer" is eventually dereferenced:
    struct S {
      T operator &() &;
    };
    
    int main() {
      S foo;
      auto p1 = &foo;  // Ok
      auto p2 = &S();  // Error
    }
    

    Can't say I've ever personally used an operator& overload.

    0 讨论(0)
提交回复
热议问题