#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;
}