#include <cstdio>	// for printf.
#include <type_traits>	// for is_reference, remove_reference.
#include <typeinfo>		// for typeid.

template<typename T>
struct mutable_value
{
	mutable_value(T val = 0) : val(val) { this->p_val = &this->val; }
	auto get_value() const -> T & { return *this->p_val; }
private:
	T val;
	T *p_val;
};

template<typename T>
struct mutable_value_for_ref
{
	typedef typename std::remove_reference<T>::type ref_dropped_t;

	mutable_value_for_ref(T ref) : p_val{ &ref }
	{
	}

	auto get_value() const -> ref_dropped_t &{ return *this->p_val; }
private:
	ref_dropped_t *p_val;
};

template<typename T>
struct unko_meta
{
	typedef
	typename std::conditional
	<
		std::is_reference<T>::value,
		mutable_value_for_ref<T>,
		mutable_value<T>
	>::type type;
};

template<typename T>
struct yakitori
{
	yakitori(T t) : x(t) { }

	auto get() const -> T & { return this->x.get_value(); }

	typename unko_meta<T>::type x;
};


auto main() -> int
{
		int i1 = 100;
		yakitori<int> const v1{ i1 };
		std::printf("--%s\n", typeid(v1.x).name());
		v1.get()++;
		std::printf("org:%d ,  yakitori:%d\n", i1, v1.get());

		int i2 = 200;
		int const &r2 = i2;
		yakitori<int const> const v2{ r2 };
		std::printf("--%s\n", typeid(v2.x).name());
		i2++;
		std::printf("org:%d ,  yakitori:%d\n", i2, v2.get());

		int i3 = 300;
		yakitori<int &> const v3{ i3 };
		std::printf("--%s\n", typeid(v3.x).name());
		v3.get()++;
		std::printf("org:%d ,  yakitori:%d\n", i3, v3.get());

		int i4 = 400;
		int const &r4 = i4;
		yakitori<int const &> const v4{ r4 };
		std::printf("--%s\n", typeid(v4.x).name());
		i4++;
		std::printf("org:%d ,  yakitori:%d\n", i4, v4.get());
}
