#include <cstdint>
#include <iostream> // for test
#include <type_traits>
#include <utility>
 
template<class T>
class pointer
{
  using this_type = pointer<T>;
  T* _ptr;
 
public:
  using value_type = T;
  using reference = value_type&;
  using const_reference = const value_type&;
  using difference_type = std::ptrdiff_t;
 
  pointer() noexcept : _ptr() {}
  pointer(T* p) noexcept : _ptr(p) {}
 
  T* get() const noexcept { return _ptr; }
 
  T* operator->() const noexcept { return _ptr; }
  reference operator*() const noexcept { return (*_ptr); }
 
  // この場合の添え字演算子は関節参照演算子のシンタックスシュガー
  reference operator[](std::ptrdiff_t diff) { return *(_ptr + diff); }
  const_reference operator[](std::ptrdiff_t diff) const { return *(_ptr + diff); }
 
  reference operator++() { ++_ptr; return (*this); }
  reference operator--() { --_ptr; return (*this); }
  value_type operator++(int) { this_type temp(*this); ++*this; return temp; }
  value_type operator--(int) { this_type temp(*this); --*this; return temp; }
 
  explicit operator bool() const noexcept { return _ptr; }
  bool operator!() const noexcept { return !static_cast<bool>(*this); }
 
  template<class U,
    std::enable_if_t<std::is_member_function_pointer<U>::value, std::nullptr_t> = nullptr>
  auto operator->*(U u) const noexcept
  {
    return [u, this](auto... args)
    { // lambda
      return (_ptr->*u)(std::forward<decltype(args)>(args)...);
    };
  }
 
  template<class U,
    std::enable_if_t<std::is_member_object_pointer<U>::value, std::nullptr_t> = nullptr>
  auto& operator->*(U u) const noexcept
  {
    return _ptr->*u;
  }
 
  reference operator+=(difference_type diff)
    { _ptr += diff; return (*this); }
  reference operator-=(difference_type diff)
    { _ptr -= diff; return (*this); }
 
};
 
template<class T, class U>
static inline bool operator==(const pointer<T>& p1, const pointer<U>& p2) noexcept
{
  return p1.get() == p2.get();
}
 
// この減算は例の厄介なやつ。
template<class T, class U>
static inline auto operator-(const pointer<T>& p1, const pointer<U>& p2)
  ->typename pointer<T>::difference_type
{
  return typename pointer<T>::difference_type(p1.get() - p2.get());
}
 
 
 
struct something
{
  void great_function() const { std::cout <<"I am great." << std::endl; }
  int great_n = 0;
};
 
int main()
{
  something s;
  pointer<something> ps(&s);
  ps->great_function();
 
  auto pgreat_func = &something::great_function;
  (ps->*pgreat_func)();
 
  auto pgreat_n = &something::great_n;
  ps->*pgreat_n = 10;
  int n = ps->*pgreat_n;
  std::cout << n << std::endl;
}