#include <iostream>
#include <vector>
using namespace std;


template< typename TBufferTypeFront, typename TBufferTypeBack = TBufferTypeFront>
class FrontBackBuffer {
	
	// If <const * int , int&> --> this result in is_same< int , int > 
	// STATIC_ASSERT( std::is_same< RemoveModifiers<TBufferTypeFront>::type, typename RemoveModifiers<TBufferTypeFront>::type>::result )
	
public:
	
    template <typename T>
    struct MyRefTypes {
        typedef T Org;
        typedef T* Ptr;
        typedef const T & Con;
        typedef T& Ref;
        typedef const T& CRef;
        static inline Ptr getUnderlyingPtr(T& v) {
            return &v;
        }
        static Ref getRef(T& v) {
            return v;
        }
    };
	
	//Specialization for Reference
    template <typename T>
    struct MyRefTypes<T&> {
        typedef T Org;
        typedef T* Ptr;
        typedef T & Con;
        typedef T& Ref;
        typedef const T& CRef;
        static inline Ptr getUnderlyingPtr(T& v) {
            return &v;
        }
        static inline Ref getRef(T& v) {
            return v;
        }
    };
	
	//Specialization for const Reference
    template <typename T>
    struct MyRefTypes<const T&> {
        typedef T Org;
        typedef T* Ptr;
        typedef const T & Con;
        typedef const T& Ref;
        typedef const T& CRef;
        static inline Ptr getUnderlyingPtr(const T& v) {
            return &const_cast<T&>(v);
        }
        static inline Ref getRef(const T& v) {
            return v;
        }
    };
	
	//Specialization for const
    template <typename T>
    struct MyRefTypes<const T> {
        typedef T Org;
        typedef T* Ptr;
        typedef const T & Con;
        typedef const T& Ref;
        typedef const T& CRef;
        static inline Ptr getUnderlyingPtr(const T& v) {
            return &const_cast<T&>(v);
        }
        static inline Ref getRef(const T& v) {
            return v;
        }
    };
	
	//Specialization for pointers
    template <typename T>
    struct MyRefTypes<T*> {
        typedef T* Ptr;
        typedef T Org;
        typedef T* Con;
        typedef T& Ref;
        typedef T* const CRef;  //! note this is a pointer....
        static inline Ptr getUnderlyingPtr(T* v) {
            return v;
        }
        static inline Ref getRef(T* v) {
            return *v;
        }
    };
	
	//Specialization for const pointers
    template <typename T>
    struct MyRefTypes<const T*> {
        typedef T Org;
        typedef T* Ptr;
        typedef const T* Con;
        typedef const T& Ref;
        typedef const T* const CRef; //! note this is a pointer....
        static inline Ptr getUnderlyingPtr(const T* v) {
            return const_cast<T*>(v);
        }
        static inline Ref getRef(const T* v) {
            return *v;
        }
    };
	
	
    typedef typename MyRefTypes<TBufferTypeFront>::Ref TBufferTypeFrontRef;
    typedef typename MyRefTypes<TBufferTypeFront>::CRef TBufferTypeFrontCRef;
    typedef typename MyRefTypes<TBufferTypeFront>::Con TBufferTypeFrontCon;
    typedef typename MyRefTypes<TBufferTypeFront>::Org TBufferTypeFrontOrg;
	typedef typename MyRefTypes<TBufferTypeFront>::Ptr TBufferTypeFrontPtr;
    
    typedef typename MyRefTypes<TBufferTypeBack >::Ref TBufferTypeBackRef;
    typedef typename MyRefTypes<TBufferTypeBack >::CRef TBufferTypeBackCRef;
    typedef typename MyRefTypes<TBufferTypeBack >::Con TBufferTypeBackCon;
    typedef typename MyRefTypes<TBufferTypeBack >::Org TBufferTypeBackOrg;
    typedef typename MyRefTypes<TBufferTypeBack >::Ptr TBufferTypeBackPtr;
	
    explicit FrontBackBuffer(
							 TBufferTypeFrontCon  front,
							 TBufferTypeBackCon   back):
	m_Front(front),
	m_Back(back)
    {
		m_pBack = MyRefTypes<TBufferTypeBack>::getUnderlyingPtr(m_Back);
		m_pFront = MyRefTypes<TBufferTypeFront>::getUnderlyingPtr(m_Front);
		
    };
	
	
    ~FrontBackBuffer()
    {};
	
    TBufferTypeFrontRef getFront() {
        return *m_pFront;
    }
    TBufferTypeBackRef getBack() {
        return *m_pBack;
    }
	
	void swap(){
		TBufferTypeFrontPtr temp = m_pFront;
		m_pFront = m_pBack;
		m_pBack = temp;
    }
	
private:
	
   
	
    TBufferTypeFrontPtr m_pFront;       ///< The pointer to front buffer
    TBufferTypeBackPtr  m_pBack;         ///< The pointer to back buffer
	
    TBufferTypeFront m_Front;       ///< The front buffer
    TBufferTypeBack m_Back;         ///< The back buffer
	
};


typedef std::vector<float> GAGAType ;

int main() {
	int front=10;
    int back=3;
    FrontBackBuffer< const int*, int & > buf1(&front, back);
    buf1.getBack() = 4; // change from 3 to 4
    // buf.getFront() = 5; NO! is const!
    buf1.swap();
	std::cout << buf1.getFront() << buf1.getBack() << std::endl;
    //NOW getBack() and getFront() should return  4 and 10!
    
	front = 1;
	back= -1;
    FrontBackBuffer<int &, int > buf2(front, back);
    buf2.getBack() = 2; 
    buf2.getFront() = 3; 
    
    buf2.swap();   
    //NOW getBack() and getFront() should return  2 and 3!
    std::cout << buf2.getFront() << buf2.getBack() << std::endl;
	
	front = 1;
	back= -1;
    FrontBackBuffer<int, const int &> buf3(front, back);
    //buf3.getBack() = 2; // IS CONST!!
    buf3.getFront() = 3; 
    
    buf3.swap();   
    //NOW getBack() and getFront() should return  -1 and 3!
    std::cout << buf3.getFront() << buf3.getBack() << std::endl;
	
}