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?
Aucun commentaire:
Enregistrer un commentaire