#include <iostream>
#include <tuple>
#include <cassert>

struct foo 
{
	foo() = delete;
	
	foo(int i, int k)
	: i(i), k(k){}
	
	void operator()()
	{ std::cout << i << " " << k << std::endl;}
	
	int i;
	int k;
};

struct bar
{
	bar() = delete;
	
	bar(int x)
	: x(x){}
	
	void operator()()
	{ std::cout << x << std::endl;}
	
	int x;
};


template <size_t I>
struct visit_impl
{
    template <typename T, typename F>
    static void visit(T& tup, size_t idx, F fun)
    {
        if (idx == I - 1) fun(std::get<I - 1>(tup));
        else visit_impl<I - 1>::visit(tup, idx, fun);
    }
};

template <>
struct visit_impl<0>
{
    template <typename T, typename F>
    static void visit(T& tup, size_t idx, F fun) { assert(false); }
};
 
/// visit at runtime the tuple item at idx and run F
template <typename F, typename... Ts>
void visit_at(std::tuple<Ts...> const& tup, size_t idx, F fun)
{
    visit_impl<sizeof...(Ts)>::visit(tup, idx, fun);
}

/// visit at runtime the tuple item at idx and run F
template <typename F, typename... Ts>
void visit_at(std::tuple<Ts...>& tup, size_t idx, F fun)
{
    visit_impl<sizeof...(Ts)>::visit(tup, idx, fun);
}

/// make an object
template <typename T, typename... Args>
T make_class(Args ...args)
{
	return T(args...);
}

template <typename... Args>
void make_classes(Args... args)
{
	auto t = std::tuple<Args...>(args...);
	unsigned int size = std::tuple_size<decltype(t)>::value;
	auto execute = [](auto & obj){ obj.operator()(); };
	
	for (int i = 0; i < size; i++) {
		visit_at(t, i, execute);
	}
}

int main() 
{
	make_classes(
				 foo(2, 6),
				 bar(3),
				 foo(10,11),
				 bar(9)
			   );
}
