#include <typeinfo>
#include <iostream>

using namespace std;

template <typename typed, int i = 1> struct enumerate
{
	static auto get(typed x) -> decltype(x.template get<i>()) { return x.template get<i>(); };
	const static bool has_next = !is_same<decltype(typed().template get<i+1>()), void>::value;
	typedef enumerate<typed, has_next?i+1:0> next;
	
	template <template <class> class handler> static void go(typed x)
	{
		handler<decltype(get(x))>()(get(x));
		if (has_next) next::template go<handler>(x);
	}
};

template <typename typed> struct enumerate <typed, 0>
{
	static void get(typed x) {}
	const static bool has_next = false;
	typedef enumerate<typed, 0> next;
	
	template <template <class> class handler> static void go(typed x)
	{
	}
};

struct smth
{
	template <int i> struct key_t {};
	
	template <int i> void get(key_t<i>) {}
	
	int x; int get(key_t<1>) { return this->x; }
	double y; double get(key_t<2>) { return this->y; }
	
	template <int i> auto get() -> decltype(this->get(key_t<i>())) { return this->get(key_t<i>()); }
};

template <class typed> void print(const typed& t)
{
	cout << t << endl;
}

template <class typed> struct pass_to_print
{
	void operator () (typed t) { return print(t); }
};

int main()
{
	smth s = {1, 2.5};
	
	cout.setf(ios::boolalpha);
	
	cout << s.x << ' ' << s.y << endl;
	cout << s.get<1>() << ' ' << s.get<2>() << endl;
	cout << endl;
	
	cout << enumerate<smth, 1>::get(s) << ' ' << enumerate<smth, 1>::has_next << endl;
	cout << enumerate<smth, 1>::next::get(s) << ' ' << enumerate<smth, 1>::next::has_next << endl;
	cout << endl;
	
	enumerate<smth>::go<pass_to_print>(s);
	
	return 0;
}