#include<memory>
#include<iostream>
#include<typeinfo>
using namespace std;

template<typename T>
struct void_ { typedef void type; };

template<typename T, typename = void>
struct My_sfinae {
  typedef T RealType;
  static T& getPtr (T &p) { return p; }
};                        //^^^^^^^^^ business logic!
template<typename T>
struct My_sfinae<T, typename void_<typename T::smart_type>::type> {
  typedef typename My_sfinae<typename T::smart_type>::RealType RealType;
  static RealType& getPtr (T &p) { return My_sfinae<typename T::smart_type>::getPtr(p.getPtr()); }
};

template<typename T>
class some_smart_ptr_wrapper
{
  T m_ptr;
public:
  typedef T smart_type;  // <-- unique name
  T& getPtr () { return m_ptr; }

  typename My_sfinae<T>::RealType& getFinalPtr () { return My_sfinae<T>::getPtr(m_ptr); }
};

int main ()
{
  shared_ptr<int> p1; 
  some_smart_ptr_wrapper<some_smart_ptr_wrapper<some_smart_ptr_wrapper<shared_ptr<int>>>> p2; 

  if(typeid(p1) == typeid(p2.getFinalPtr()))
    cout << "working\n";
  else
    cout << "not working\n";
} 
