#include <utility>
#include <memory>
#include <iostream>

template<class T>
T&& smart_wrap_unwrap(T&& v, long)
{
  return std::forward<T>(v);
}

template<class T>
auto smart_wrap_unwrap(T&& v, int)
  -> decltype(smart_wrap_unwrap(std::forward<T>(v).getPtr(), 0))
{
  return smart_wrap_unwrap(std::forward<T>(v).getPtr(), 0);
}

template<class T>
struct smart{
  template<class U>
  smart(U* v) : _ptr(v){}
  T& getPtr(){ return _ptr; }
  T _ptr;
};

struct X{
  void foo(){ std::cout << "!\n"; }
};

int main(){
  smart<smart<smart<std::shared_ptr<X>>>> smartception(new X());
  smart_wrap_unwrap(smartception, 0)->foo();
}