I am a bit stumped by the following conversion problem in C++11. Given this code:
#include <utility>
struct State {
State(State const& state) = default;
State(State&& state) = default;
State() = default;
int x;
};
template<typename T>
struct Wrapper {
T x;
Wrapper() = default;
operator T const&() const& { return x; }
// version which also works with GCC 4.9.2:
// operator T&&() && { return std::move(x); }
// version which does not work with GCC 4.9.2:
operator T() && { return std::move(x); }
};
int main() {
Wrapper<State> x;
State y(std::move(x));
}
godbolt link to the failed compilation with Clang
In the form above, g++ starting at version 5.1 and ICPC version 16 and 17 compile the code. If I uncomment the T&&
conversion operator and comment-in the currently-used second one:
operator T&&() && { return std::move(x); }
// version which does not work with GCC 4.9.2:
// operator T() && { return std::move(x); }
then GCC 4.9 also compiles. Otherwise, it complains:
foo.cpp:23:23: error: call of overloaded ‘State(std::remove_reference<Wrapper<State>&>::type)’ is ambiguous
State y(std::move(x));
^
foo.cpp:23:23: note: candidates are:
foo.cpp:5:3: note: constexpr State::State(State&&)
State(State&& state) = default;
^
foo.cpp:4:3: note: constexpr State::State(const State&)
State(State const& state) = default;
However, clang never compiles the code, equally complaining about an ambiguous call to the constructor of State
.
This, I do not understand. Given the std::move(x)
, I would expect to have an rvalue of type Wrapper<State>
. Then, shouldn’t the conversion operator T&&() &&
be clearly better than the T const&() const&
one? And given that, shouldn’t the rvalue-reference constructor of State
be used to construct y
from the rvalue-reference return value of the conversion?
Can someone explain the ambiguity to me and ideally also whether Clang or GCC (and if so, in which version) is right and what would be the best way to achieve the move out of the wrapper into the state object?