Do rvalue references satisfy the Cpp17MoveConstructible requirement?
For this to be the case, in the expression T u = rv;, u would need to be "equivalent" to rv. If T was an rvalue reference (e.g. int&&), then in int&& u = 0;, u would need to be "equivalent" to 0. However, is a reference ever equivalent to a value, or does it merely refer to an object which is equivalent?
Motivation
The reason I'm asking is because it's unclear to me how std::swap<int&&> should behave.
is_move_constructible_v<int&&> and is_move_assignable_v<int&&> are true, so the constraints of std::swap are satisifed and it can be instantiated.
However, the effect of swap<int&&> is undefined if int&& does not satisfy Cpp17MoveConstructible.
In fact, all major implementations (libc++, libstdc++, MSVC STL) implement std::swap(a, b) along the lines of:
T t = std::move(a);
a = std::move(b);
b = std::move(t);
If T is an rvalue reference, then T t = _MOVE(a) is not creating a move-constructed copy, but binding an rvalue reference to another rvalue reference.
For T = int&&, the effect is then equivalent to:
a = a;
b = a;
What do we make of this?
- Rvalue references do not satisfy Cpp17MoveConstructible. All implementations are correct. The preconditions of
swapare not satisfied so it can be have like this. - Rvalue references satisfy Cpp17MoveConstructible. All implementations are wrong.
Well, which is it?
Note: Issue LWG4047 "Explicitly specifying template arguments for std::swap should not be supported" addresses some of the concerns here.
No one knows, not even the committee.
This question has first been asked in LWG2146 Are reference types
Copy/Move-Constructible/AssignableorDestructible?, in March 2012.It is an open issue with no clear consensus, and the exact same concern about explicitly calling e.g.
std::swap<int&&>(x, y)orstd::for_each<int*, F&&>gets brought up in this issue. Some of these problems have since been solved, namely:std::for_eachcase is banned as per [algorithms.requirements] p15 (calling algorithms with explicitly-specified template arguments is unspecified behavior).std::threadconstructor was fixed through use ofdecay_t.However: "The swap case still needs solving. Still need a survey."