#include <iostream>
#include <typeinfo> 
#include <memory>

struct nil		{ };

//スマートポインタを生ポインタと同様に扱うための変換
//int -> nil*,  int* -> int*,  smart_ptr<int> -> int*
template <typename T>
	class dereferencable	{
		static T getT();
		template <typename U>
			static std::true_type test1(U&& u, decltype(*u, 0) = 0);	//本来はtest1だけでOKのはず
		template <typename U>
			static std::true_type test2(U&& u, typename std::enable_if<std::is_same<	//workaround for VC2012
								typename std::remove_cv<typename std::remove_reference<decltype(&*u)>::type>::type,
								typename std::remove_cv<typename std::remove_reference<decltype(&u)>::type>::type
										>::value>::type* = 0 );
		static std::false_type	test1(...);
		static std::false_type	test2(...);
		typedef decltype(test1(getT()))	T1;
		typedef decltype(test2(getT()))	T2;
		typedef typename std::conditional<T1::value && !T2::value, T, nil*>::type  psp_type; 
		static psp_type	getPSP();
	public:
		static const bool value = (T1::value && !T2::value);	//int -> false,  int* -> true,  s_ptr<int> -> true
		typedef decltype(&*getPSP())	p_type;		//int -> nil*,  int* -> int*,  s_ptr<int> -> int*
	};

 int  main()
{
	int v=9;
	int* p = &v;
	std::unique_ptr<int> sp(new int(14312421));

	std::cout << dereferencable<decltype(v)>::value << std::endl;
	std::cout << dereferencable<decltype(p)>::value << std::endl;
	std::cout << dereferencable<decltype(sp)>::value << std::endl;
	
	std::cout << typeid(nil*).name() << " : " <<
		typeid(dereferencable<decltype(v)>::p_type).name() << std::endl;
	std::cout << typeid(int*).name() << " : " <<
		typeid(dereferencable<decltype(p)>::p_type).name() << std::endl;
	std::cout << typeid(int*).name() << " : " <<
		typeid(dereferencable<decltype(sp)>::p_type).name() << std::endl;


	return 0;
}