mardi 31 janvier 2017

Conversion and move ctor leads to ambiguous call for Clang and GCC 4.9.2

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