#include <iostream>
#include <iomanip>
#include <type_traits>

struct move_not_copy { move_not_copy(move_not_copy &&); };

template<typename T>
struct has_move_constructor {
	struct helper : public move_not_copy,  public T {
	};
	constexpr static bool value = std::is_constructible<helper, typename std::add_rvalue_reference<helper>::type> ::value;
	constexpr operator bool () const { return value; }
};

struct T0 {
	void operator=(T0&&) {}
};
struct Copy {
   Copy( const Copy& );
};
struct MoveOnly {
   MoveOnly( MoveOnly&& );
};
struct Both {
   Both( const Both& );
   Both( Both&& );
};
struct CopyWithDeletedMove {
   CopyWithDeletedMove( const CopyWithDeletedMove& );
   CopyWithDeletedMove( CopyWithDeletedMove&& ) = delete;
};

template<typename T>
void provide_a_report_impl(const char *type_name) {
	std::cout << std::setw(20) << type_name
		<< "  is_copy_constructible " << std::is_constructible<T, typename std::add_lvalue_reference<T>::type>()
		<< "  is_move_constructible " << std::is_constructible<T, typename std::add_rvalue_reference<T>::type>()
		<< "  has_move_constructor " << has_move_constructor<T>::value
		<< std::endl;
};
#define REPORT_ON_ISHAS_MOVE_CONSTRUCTOR(T) provide_a_report_impl<T>(#T)

int main()
{
   REPORT_ON_ISHAS_MOVE_CONSTRUCTOR(Copy);
   REPORT_ON_ISHAS_MOVE_CONSTRUCTOR(MoveOnly);
   REPORT_ON_ISHAS_MOVE_CONSTRUCTOR(Both);
   REPORT_ON_ISHAS_MOVE_CONSTRUCTOR(CopyWithDeletedMove);
}