#include <iostream>
#include <utility>
#include <tuple>

namespace details
{

template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
  for_each(const std::tuple<Tp...> &, FuncT) // Unused arguments are given no names.
  { }

template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
  for_each(const std::tuple<Tp...>& t, FuncT f)
  {
    f(std::get<I>(t));
    for_each<I + 1, FuncT, Tp...>(t, f);
  }

template <typename T>
struct traverseType
{
	void operator () (const T& t)
	{
		std::cout << "it is a generic T:" << t << std::endl;
	}
};

template <>
struct traverseType<int>
{
	void operator () (int i)
	{
		std::cout << "it is a int:" << i << std::endl;
	}
};

struct traverseTypeCaller
{
	template <typename T>
	void operator () (const T& t)
	{
		details::traverseType<T>()(t);
	}
};

template <typename ...T>
struct traverseType<std::tuple<T...>>
{
	void operator () (const std::tuple<T...>& t)
	{
		std::cout << "it is a tuple:" << std::endl;
		for_each(t, traverseTypeCaller());
	}
};

}

template <typename T>
void traverseType(const T& t)
{
	details::traverseTypeCaller()(t);
}

int main()
{
	const auto t = std::make_tuple(42, '*', std::make_tuple(4, 2));

	traverseType(t);

	return 0;
}
