#include <iostream>
#include <vector>
#include <algorithm>

void do_something_on_A(int &a) { std::cout << "\tA is " << a << '\n'; }
void do_something_on_B(int &b) { std::cout << "\tB is " << b << '\n'; }

template <typename F, typename T, template<typename, typename> class V>
void iterate_all(V<T, std::allocator<T>> &xyz, F func)
{
	for (auto &v : xyz)
	{
		std::cout << "Iterating innermost container\n";
		func(v);
	}
}

template <typename F, typename T, template<typename, typename> class V> 
void iterate_all(V<V<T, std::allocator<T>>, std::allocator<V<T, std::allocator<T>>>> &xyz, F func)
{
	for (auto &v : xyz)
	{
		std::cout << "Iterating container of containers\n";
		iterate_all(v, func);
	}
}
/*
template <typename F, typename T, int X, int Y, int Z> void iterate_all(T (&xyz)[X][Y][Z], F func)
{
	const int limit = X * Y * Z;
	int index = 0;

	while (index < limit)
	{
		int x = index % X,
			y = (index / X) % Y,
			z = index / (X * Y);

		++index;

		std::cout << "Doing something on " << x << ' ' << y << ' ' << z << '\n';
		func(xyz[x][y][z]);
	}
}
*/
template<typename F, typename A> typename std::enable_if< std::rank<A>::value == 1 >::type
iterate_all(A &xyz, F func)
{
	for (auto &v : xyz)
	{
		std::cout << "Iterating innermost array\n";
		func(v);
	}
}

template<typename F, typename A> typename std::enable_if< std::rank<A>::value != 1 >::type
iterate_all(A &xyz, F func)
{
	for (auto &v : xyz)
	{
		std::cout << "Iterating array of arrays\n";
		iterate_all(v, func);
	}
}

int main()
{
	using V0 = std::vector< std::vector< std::vector<int> > >;
	using V1 = std::vector< std::vector< std::vector< std::vector< std::vector<int> > > > >;

	V0 A0 =   {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}};
	V1 A1 = {{{{{9, 8}, {7, 6}}, {{5, 4}, {3, 2}}}}};

    int B0[10][8][5] = {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}};
    int B1[7][11][8] = {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}};
    int B2[2][2][2][2][2][2] = {{{{{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}}}}};

	iterate_all(A0, do_something_on_A);
	iterate_all(A1, do_something_on_A);

	iterate_all(B0, do_something_on_B);
	iterate_all(B1, do_something_on_B);
	iterate_all(B2, do_something_on_B);

	return 0;
}