18

Recently I learned about function's reference qualifiers, e.g.

struct foo
{
    void bar() {}
    void bar1() & {}
    void bar2() && {}
};

Where I might need this feature, is there any real use case for this language feature ?

Praetorian
  • 100,267
  • 15
  • 224
  • 307
tommyk
  • 2,853
  • 4
  • 33
  • 54
  • Related: http://stackoverflow.com/questions/8610571/what-is-rvalue-reference-for-this – Caramiriel Jan 19 '15 at 14:05
  • 3
    The most useful way I know is using for *convertion operator* overloading `struct foo { operator std::string () const & { return s; } operator std::string () && { return std::move(s); } std::string s; };`. Therefore `foo func() { return {"string"s}; } ... std::string s = foo();` not imply unnecessary copying and destruction of nonempty `std::string` object. – Tomilov Anatoliy Jan 20 '15 at 14:37
  • @Orient please add this as an answer as it's really interesting and might be helpful for somebody. – tommyk Jan 21 '15 at 10:34

2 Answers2

29

Where I might need this feature, is there any real use case for this language feature ?

The example you show is pretty useless, it's more useful when you have an overloaded function, one version that operates on lvalues and one that operates on rvalues.

Consider a type a bit like std::stringstream that owns a string and returns it by value. If the object is an rvalue, it can move the string instead of copying it.

class StringBuilder
{
public:
  std::string get() const& { return m_str; }
  std::string get() && { return std::move(m_str); }

private:
  std::string m_str;
};

This means when you return a StringBuilder from a function and want to get the string out of it, you don't need a copy:

std::string s = buildString().get();

More generally, given a function f(const X&) if it would be useful to overload it with f(X&&), then given a member function X::f() it might be useful to change it to X::f() const& and overload it with X::f()&&

Jonathan Wakely
  • 153,269
  • 21
  • 303
  • 482
17

There are basically two uses:

  1. To provide an optimized overload, for example to move a member out of a temporary object instead of having to copy it.
  2. Prevent misuse of an API. For example, no one would expect

    int a = 1 += 2;
    

    to work and this would also cause a compile error. However

    string b = string("foo") += "bar";
    

    is legal if operator += is declared as

    string & operator += (string const & o);
    

    as is usually the case. Also this has the nasty side-effect of providing an lvalue-reference to your rvalue. Bad idea. This can easily be prevented by declaring the operator as

    string & operator += (string const & o) &;
    
Joe
  • 5,877
  • 1
  • 27
  • 51