#include <typeinfo>
#include <iostream>

using namespace std;

template <typename typed, int i = 0> 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:-1> 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, -1>
{
	static void get(typed x) {}
	const static bool has_next = false;
	typedef enumerate<typed, -1> next;
	
	template <template <class> class handler> static void go(typed x)
	{
	}
};

#define ENUMERABLE_FIELD(type, name, i) public: type name; \
                                        private: type get(key_t<i>) { return this->name; }

struct smth
{
	private: template <int i> struct key_t {};
	private: template <int i> void get(key_t<i>) {}
	
	ENUMERABLE_FIELD(int, x, 0)
	ENUMERABLE_FIELD(double, y, 1)
	
	public: 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};

	enumerate<smth>::go<pass_to_print>(s);
	
	return 0;
}