Are rvalue references Cpp17MoveConstructible?

74 Views Asked by At

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 swap are 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.

1

There are 1 best solutions below

0
Jan Schultke On

Are rvalue references Cpp17MoveConstructible?

No one knows, not even the committee.

This question has first been asked in LWG2146 Are reference types Copy/Move-Constructible/Assignable or Destructible?, 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) or std::for_each<int*, F&&> gets brought up in this issue. Some of these problems have since been solved, namely:

  • The std::for_each case is banned as per [algorithms.requirements] p15 (calling algorithms with explicitly-specified template arguments is unspecified behavior).
  • The std::thread constructor was fixed through use of decay_t.

However: "The swap case still needs solving. Still need a survey."