#include <iostream>
#include <type_traits>

struct BrokenDataWrapperByMoveOrCopy;

struct Data {
  Data()                 { std::cout << "  constructor\n";}
  Data(const Data& data) { std::cout << "  copy constructor\n";} 
  Data(Data&& data)      { std::cout << "  move constructor\n";}
  explicit Data(int i) { std::cout << " explicitly constructed from int\n";}
  private:
  explicit Data(void* p)  { std::cout << " only my friend knows how to construct me from a void*\n"; }
  friend BrokenDataWrapperByMoveOrCopy;
};

struct DataWrapperByMoveOrCopy {
  Data data_;
  template<typename T, 
  	typename = typename std::enable_if<
  		std::is_same<typename std::decay<T>::type, Data>::value
  	>::type
  >
  DataWrapperByMoveOrCopy(T&& data) : data_(std::forward<T>(data)) { }
};

struct BrokenDataWrapperByMoveOrCopy {
  Data data_;
  template<typename T>
  BrokenDataWrapperByMoveOrCopy(T&& data) : data_(std::forward<T>(data)) { }
};

int main() {
  
  std::cout << "1. DataWrapperByMoveOrCopy:\n";  
  Data d1;
  DataWrapperByMoveOrCopy a1(std::move(d1));
  
  std::cout << "2. BrokenDataWrapperByMoveOrCopy:\n";  
  int d2;  //oops is an int rather than a Data
  BrokenDataWrapperByMoveOrCopy a2(std::move(d2));  //this compiles, ouch
  
  std::cout << "3. DataWrapperByMoveOrCopy:\n";  
  int d3;  //oops is an int rather than a Data
  //DataWrapperByMoveOrCopy a3(std::move(d3));  //this failes as its supposed to
  
  std::cout << "4. BrokenDataWrapperByMoveOrCopy:\n";  
  int* p = nullptr;
  BrokenDataWrapperByMoveOrCopy a4(p);  //this compiles, this is terrible

}