13

The following code compiles without problem on gcc 4.8.1:

#include <utility>

struct foo
{
};

int main()
{
    foo bar;

    foo() = bar;
    foo() = std::move( bar );
}

It seems the implicitly generated assignment operators for foo are not & ref-qualified and so can be invoked on rvalues. Is this correct according to the standard? If so, what reason is there for not requiring implicitly generated assignment operators to be & ref-qualified?

Why doesn't the standard require the following to be generated?

struct foo
{
  foo & operator=( foo const & ) &;

  foo & operator=( foo && ) &;
};
Andrew Durward
  • 3,771
  • 1
  • 19
  • 30
  • 1
    Keep in mind there were implicit copy assignment operators before there was C++11, and thus before there were ref-qualifiers for non-static member functions. That and the philosophy of the Standard Committee when it comes to compiling former C++ code with a newer compiler. – Luc Danton Jun 08 '13 at 08:20
  • @Luc For some reason backwards compatibility didn't occur to me until after I'd posted the question. I'd forgotten that typical cost/benefit analysis doesn't apply when considering changes to the standard. – Andrew Durward Jun 08 '13 at 13:15
  • Related: https://stackoverflow.com/questions/53007802/ – M.M Dec 21 '19 at 23:21

2 Answers2

9

Well, there are certain legitimate use cases for assigning to an rvalue. To quote from Ref-qualifiers for assignment operators in the Standard Library:

There are only a few very specific types for which it makes sense to support assigning to an rvalue. In particular, types that serve as a proxy, e.g., vector<bool>::reference, and types whose assignment operators are const-qualified (e.g., slice_array).

The C++ standard committee obviously felt that default assignment should not have an implicit ref qualifier - rather it should be explicitly declared. Indeed, there may be existing code which would stop working if all of a sudden all implicitly declared assignment operators didn't work with rvalues.

Granted, it's a bit hard to contrive an example where we want an implicitly declared assignment operator to work with rvalues, but the C++ standard committee likely doesn't want to take these kind of chances when it comes to preserving backwards compatibility. Code like this:

int foo_counter = 0;

struct Foo
{
    Foo()
    {
        ++foo_counter;
    }

    ~Foo()
    {
        --foo_counter;
    }
};

int main()
{
    Foo() = Foo();
}

...wouldn't work anymore. And at the end of the day, the standards committee wants to make sure that previously valid C++ (no matter how stupid or contrived) continues to work in C++11.

Charles Salvia
  • 52,325
  • 13
  • 128
  • 140
  • 1
    It seems they've applied the same logic (re: backwards compatibility) to the linked proposal since the issue was closed as "not a defect." So all instances of `std::string() = std::string()` will remain valid (for better or worse). – Andrew Durward Jun 08 '13 at 10:58
2

It seems like your question is more "Why would assignment to an rvalue ever be useful?" rather than "Why doesn't the standard ref-qualify auto generated constructors?"

The reason assignment to an rvalue is allowed is because there are some cases where it is useful.

One example usage is with std::tie (link):

#include <set>
#include <tuple>

int main()
{
    std::set<int> s;

    std::set<int>::iterator iter;
    bool inserted;

    // unpacks the return value of insert into iter and inserted
    std::tie(iter, inserted) = s.insert(7);
}

Example borrowed from cppreference.com then modified

Timothy Shields
  • 75,459
  • 18
  • 120
  • 173
  • 2
    This doesn't really answer the question because the OP is specifically asking about implicitly declared assignment operators, not assigning to rvalues in general – Charles Salvia Jun 08 '13 at 03:08
  • @CharlesSalvia Hmm maybe you're right. I answered in a hurry and slightly misunderstood the question. Your answer more directly answers it. – Timothy Shields Jun 08 '13 at 03:10