#include <boost/type_traits.hpp>
#include <utility>
#include <iostream>
#include <deque>
#include <stack>

namespace detail {
template<typename T, typename U> 
struct clone_const { 
  typedef U type;
};

template<typename T, typename U>
struct clone_const<T const, U> {
  typedef U const type;
};

template<typename T, typename R, typename... Ps>
struct clone_const<T const, R(Ps...)> {
  typedef R type(Ps...) const;
};

template<class T, class V,
         bool = !boost::is_function<T>::value>
struct mixin {
  typedef typename clone_const<V, T>::type const_type;
  V &v; T V::*m;
  mixin(V&v,T V::*m):v(v),m(m) {}
  
  typedef const_type &r_type;
  template<typename...U> r_type &operator()(U&&...) 
    { return v.*m; }
};

template<class T, class V>
struct mixin<T,V,false> {
  typedef typename clone_const<V,T>::type const_type;
  V &v; const_type V::*m;
  mixin(V&v,const_type V::*m):v(v),m(m){}
  
  typedef typename boost::function_traits<T>::result_type r_type;
  template<typename...U> r_type operator()(U&&...u) 
    { return (v.*m)(std::forward<U>(u)...); }
};
}

#define GIMME(T,B,M,A)                                      \
  __extension__ ({                                          \
      struct GIMME_impl {                                   \
        typedef boost::remove_const<B>::type base;          \
        struct GIMME_voyeur : base { using base::M; };      \
        detail::mixin<T,B>::r_type operator()(B &b) {       \
          return detail::mixin<T,B>(b, &GIMME_voyeur::M) A; \
        }                                                   \
      } gimme_obj_; gimme_obj_; }) 

struct X {
  void print() const { 
    std::cout << y << std::endl;
  }
protected:
  int y;
  void clear() { y = 0; }
};

int main() {
  X x;
  GIMME(int, X, y, ())(x) = 42;
  x.print();
  GIMME(void(), X, clear, ())(x);
  x.print();
  GIMME(void(), X const, print, ())(x);

  std::stack<int> s;
  s.push(1); s.push(2);
  GIMME(std::deque<int>, std::stack<int>, c, ())(s)
    .push_back(12);
  std::cout << s.size() << std::endl; // 3
}
