Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I use lvalue reference qualifiers for assignment operators?

Recently, I have followed a discussion about assignments to expressions in C++ as shown in the following example:

string s1, s2, s3;
(s1 + s2) = s3;

With C++11 it is possible to restrict the assignment operator to lvalue references (on the left side). When declaring the assignment operators as follow, the compiler Clang rejects the code with an error message due to incompatible types.

auto operator=(const string& rhs) & -> string&;
auto operator=(string&& rhs) & -> string&;

I haven't seen this anywhere. Is there a good reason for not using lvalue reference qualifiers for assignment operators (besides missing support in most compilers)?

like image 532
nosid Avatar asked Oct 06 '12 11:10

nosid


People also ask

What is ref qualifier?

Ref-qualifiers are used to choose between normal and rvalue reference semantics, allowing the compiler to use either copy or move semantics depending on which are more appropriate, and are applied to *this instead of this . Note that despite ref-qualifiers using reference syntax, this itself is still a pointer.

Why do we need assignment operators?

Assignment operators are used to assigning value to a variable. The left side operand of the assignment operator is a variable and right side operand of the assignment operator is a value.


2 Answers

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.

like image 162
Dietmar Kühl Avatar answered Oct 23 '22 06:10

Dietmar Kühl


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.

like image 30
Puppy Avatar answered Oct 23 '22 07:10

Puppy