Should I use lvalue reference qualifiers for assignment operators?

Is there a good reason for not using lvalue reference qualifiers for assignment operators (besides missing support in most compilers)?

No, not really. Using lvalue or rvalue qualifiers to construct a correct interface for lvalue or rvalue objects is just the same as using const, and it should be approached the same way- each function should be considered for restriction. Assignment to an rvalue doesn't really make sense, so it should be forbidden.

The reason you haven't seen it is mostly poor compiler support- rvalue refs for *this is kinda like thread_local, most compiler implementers seem to have put it near the bottom of the "Features to implement from C++11" stack.


Interesting! I wasn't even aware of this and took me while to find it (it was part of the "Extending move semantics to *this" proposal). The notation is defined in 8.3.5 [dcl.decl] paragraph 4 in case anybody wants to have a look.

Anyway: Now, knowing about this feature it seems it is most useful to use it for overloading and possibly behave differently if the object on which a function is called is an lvalue or an rvalue. Using it to restrict what can be done, e.g., with the result of an assignment seems unnecessary, especially if the object actually happens to be an lvalue. For example, you might want the syntax to return an rvalue from assigning to an rvalue:

struct T {
    auto operator=(T&) & -> T&;
    auto operator=(T&&) & -> T&;
    auto operator=(T&) && -> T;
    auto operator=(T&&) && -> T;
};

The intention here would be to enable moving from the assignment result (whether that is worth it, though, I'm not sure: why not skip the assignment in the first place?). I don't think that I would use this feature primarily to restrict uses.

Personally, I like the possibility to sometimes get hold of an lvalue from an rvalue and the assignment operator is often a way to do this. For example, if you need to pass an lvalue to a function but you know you don't want to use anything with it, you can use the assignment operator get hold of an lvalue:

#include <vector>
void f(std::vector<int>&);
int main()
{
    f(std::vector<int>() = std::vector<int>(10));
}

This may be an abuse of the assignment operator to get an lvalue from an rvalue but it is unlikely to happen by accident. Thus, I wouldn't go out of my way and make this impossible by restricting the assignment operator to be applicable to lvalues only. Of course, returning an rvalue from an assignment to an rvalue would also prevent this. Which of the two uses is more useful, if any, might be a consideration.

BTW, clang seems to support the syntax you quoted since version 2.9.