0

Consider the following snippet of code where I have a move-only Wrapper object that forwards the arguments to the underlying data on construction. Now if I use this Wrapper object inside another move-only class (SomeObject in this case), unless the move constructor for SomeObject is defaulted, it doesn't compile.

#include <utility>

template <typename T> class Wrapper {
public:
  template <typename... Args>
  Wrapper(Args &&... args) : _data{std::forward<Args>(args)...} {}

  Wrapper(const Wrapper &) = delete;

  Wrapper(Wrapper &&other) : _data(std::move(other)) {}

  T &get() const { return _data; }

protected:
  T _data;
};

struct SomeObject {
  SomeObject(const SomeObject &) = delete;
  SomeObject(SomeObject &&other) : x(std::move(other.x)) {}
  //SomeObject(SomeObject &&other) = default; // this works!
  SomeObject(int val) : x(val) {}

  Wrapper<int> x;
};

int main() {
  SomeObject obj(10);
  return 0;
}

With gcc 6.3 we get:

test.cpp: In instantiation of ‘Wrapper<T>::Wrapper(Wrapper<T>&&) [with T = int]’: 
test.cpp:20:56:   required from here 
test.cpp:10:52: error: cannot convert ‘std::remove_reference<Wrapper<int>&>::type {aka Wrapper<int>}’ to ‘int’ in initialization
Wrapper(Wrapper &&other) : _data(std::move(other)) {}
                                                ^

Is there something I am missing here? Aren't the user provided move constructor in SomeObject the same as the one the compiler would define when defaulted?

The only thing close to this that I could find is this answer but I feel like this is a different case since my move constructor for SomeObject isn't passing const types.

Tareq A. Siraj
  • 424
  • 3
  • 9

1 Answers1

1

This is expected. Look at your code:

Wrapper(Wrapper &&other) : _data(std::move(other)) {}
T _data;

in your case, T is int. How do you want to initialize int from Wrapper<int>?

SergeyA
  • 61,605
  • 5
  • 78
  • 137