On 17 October 2022 12:38:32 BST, "Peter Sommerlad (C++) via Std-Proposals" <std-proposals@lists.isocpp.org> wrote:
>
>struct X{};
>auto & dangle = (X{} = X{});
The main issue here seems to be to return a reference from the assignment at all. And if `rvalue = something` returns a reference, it should better be an rvalue reference. If the object is expiring, then it is still expiring after you assign to it.
But we write the copy assignment operator as X& X::X(X&), and the move assignment operator as [X&] X::X(X&&); the implicit object parameter is not ref-qualified, so it can accept any value category, but for historical reasons it always returns lvalue. And this is what the automatically-generated assignment operators do as well.
Are you proposing to double the number of required/supported assignment operator overloads?
I think the first-order proposal here is for user-defined types to stop returning a reference from operator= at all. Programmers should just be able to return `void` from operator= wherever possible. Unfortunately that can't easily be supported for historical reasons:
struct X {
void operator=(const X&) = default; // Proposal: Make this compile
};
struct RuleOfZero {};
RuleOfZero z;
z = z = z; // Caveat: But this C/C++98 code must continue to compile successfully
And C++20 Ranges made the situation exponentially worse by requiring all user-defined iterator types to proliferate the "reference-returning assignment" antipattern. So now such a proposal would also need to change the library side of things, too:
struct It {
using value_type = int;
using difference_type = int;
It();
It(const It&);
void operator=(const It&); // N.B.: void, not It&; this line breaks the static_assert below
int operator*() const;
It& operator++();
void operator++(int); // N.B.: this line is actually already OK in C++20
};
static_assert(std::input_iterator<It>); // Proposal: make this static_assert compile
template<std::input_iterator It>
It user_defined_algorithm(It& first) {
return first = It(); // Proposal: designate this C++20 code as undesirable, and actively break it
}
I think these changes would all be great, but I think the relevant ship sailed in C++98 and then pretty much fell off the edge of the earth in C++20.
–Arthur