#include <iostream>

struct nil {};
template <int head, typename tail> struct cons;

template <int... list> struct variadic2list;
template <int head, int... rest>
struct variadic2list<head, rest...> {
	typedef cons<head, typename variadic2list<rest...>::type> type;
};
template <> struct variadic2list<> { typedef nil type; };

template <typename typelist>
struct printlist {
	template <typename T>
	static void print(T& os) {}
};
template <int head, typename tail>
struct printlist<cons<head, tail>> {
	template <typename T>
	static void print(T& os) {
		os << head;
		printlist<tail>::print(os);
	}
};

template <int val, int count, typename rest> struct single_look_and_say;
template <int val, int count, int next, typename rest>
struct single_look_and_say<val, count, cons<next, rest>> {
	typedef cons<count, cons<val, typename single_look_and_say<next, 1, rest>::type>> type;
};
template <int val, int count, typename rest>
struct single_look_and_say<val, count, cons<val, rest>> {
	typedef typename single_look_and_say<val, count + 1, rest>::type type;
};
template <int val, int count>
struct single_look_and_say<val, count, nil> {
	typedef typename variadic2list<count, val>::type type;
};

template <size_t iters, typename seq> struct look_and_say_impl;
template <size_t iters, int head, typename tail>
struct look_and_say_impl<iters, cons<head, tail>> {
	typedef typename look_and_say_impl<iters - 1,
		typename single_look_and_say<head, 1, tail>::type>::type type;
};
// I need to pull apart head and tail to tell the compiler that this is more specialized.
template <int head, typename tail>
struct look_and_say_impl<1, cons<head, tail>> {
	typedef cons<head, tail> type;
};

template <size_t iters, int... seed>
struct look_and_say {
	typedef typename look_and_say_impl<iters, typename variadic2list<seed...>::type>::type type;
};
// Seed defaults to 1
template <size_t iters>
struct look_and_say<iters> {
	typedef typename look_and_say<iters, 1>::type type;
};

int main() {
	printlist<look_and_say<6>::type>::print(std::cout);       // 6th value
	std::cout << '\n';
	printlist<look_and_say<4, 2, 2>::type>::print(std::cout); // 4th value from 22
	return 0;
}