For an array with multiple dimensions, we usually need to write a for loop for each of its dimensions. For example:
vector< vector< vector
Something like this can help:
template
void for_each3d(const Container &container, Function function)
{
for (const auto &i: container)
for (const auto &j: i)
for (const auto &k: j)
function(k);
}
int main()
{
vector< vector< vector > > A;
for_each3d(A, [](int i){ std::cout << i << std::endl; });
double B[10][8][5] = { /* ... */ };
for_each3d(B, [](double i){ std::cout << i << std::endl; });
}
In order to make it N-ary we need some template magic. First of all we should create SFINAE structure to distinguish whether this value or container. The default implementation for values, and specialisations for arrays and each of the container types. How @Zeta notes, we can determine the standard containers by the nested iterator type (ideally we should check whether the type can be used with range-base for or not).
template
struct has_iterator
{
template
constexpr static std::true_type test(typename C::iterator *);
template
constexpr static std::false_type test(...);
constexpr static bool value = std::is_same<
std::true_type, decltype(test::type>(0))
>::value;
};
template
struct is_container : has_iterator {};
template
struct is_container : std::true_type {};
template
struct is_container : std::true_type {};
template
struct is_container> : std::true_type {};
Implementation of for_each is straightforward. The default function will call function:
template
typename std::enable_if::value, void>::type
rfor_each(const Value &value, Function function)
{
function(value);
}
And the specialisation will call itself recursively:
template
typename std::enable_if::value, void>::type
rfor_each(const Container &container, Function function)
{
for (const auto &i: container)
rfor_each(i, function);
}
And voila:
int main()
{
using namespace std;
vector< vector< vector > > A;
A.resize(3, vector >(3, vector(3, 5)));
rfor_each(A, [](int i){ std::cout << i << ", "; });
// 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
std::cout << std::endl;
double B[3][3] = { { 1. } };
rfor_each(B, [](double i){ std::cout << i << ", "; });
// 1, 0, 0, 0, 0, 0, 0, 0, 0,
}
Also this will not work for pointers (arrays allocated in heap).