I am learning C ++ fold expressions and it is really nice to deploy one package of parameters. But what if I need to expand several of them with one call?
I prepared one example to clarify what I mean:
#include <cstddef> #include <iostream> #include <utility> template< template<size_t ix_, size_t iy_> typename Functor, typename FunctorContext, size_t... ix, size_t... iy> void RepeatImpl( FunctorContext* context, std::index_sequence<ix...>, std::index_sequence<iy...>) { (Functor<ix, iy>::Execute(context), ...); } template< template<size_t ix_, size_t iy_> typename Functor, size_t width, size_t height, typename FunctorContext> void Repeat(FunctorContext* context) { RepeatImpl<Functor>( context, std::make_index_sequence<width>(), std::make_index_sequence<height>()); } template<size_t ix, size_t iy> struct Init2dArrayFunctor { template<typename T> static void Execute(T* array) { array[iy][ix] = 10; } }; int main(int, const char**) { constexpr size_t w = 10; constexpr size_t h = 10; int array[w][h] { 0 }; Repeat<Init2dArrayFunctor, w, h>(array); for(size_t iy = 0; iy < h; ++iy) { for(size_t ix = 0; ix < w; ++ix) { std::cout << array[iy][ix] << ' '; } std::cout << std::endl; } return 0; }
My question is about this line:
(Functor<ix, iy>::Execute(context), ...);
In this particular example, it will be expanded for these calls:
Functor<0, 0>::Execute(context) Functor<1, 1>::Execute(context) Functor<2, 2>::Execute(context) ...
But I need it to call all combinations of ix and iy packages:
Functor<0, 0>::Execute(context) Functor<0, 1>::Execute(context) Functor<0, 2>::Execute(context) ... Functor<1, 0>::Execute(context) Functor<1, 1>::Execute(context) Functor<1, 2>::Execute(context) ...
I know that I can make an extra layer to walk through rows and columns (then twice in separate methods):
#include <cstddef> #include <iostream> #include <utility> template< template<size_t ix_, size_t iy_> typename Functor, size_t iRow, typename FunctorContext, size_t... iColumn> void RepeatImpl_Row( FunctorContext* context, std::index_sequence<iColumn...>) { (Functor<iColumn, iRow>::Execute(context), ...); } template< template<size_t ix_, size_t iy_> typename Functor, size_t columns, typename FunctorContext, size_t... iRow> void RepeatImpl( FunctorContext* context, std::index_sequence<iRow...>) { (RepeatImpl_Row<Functor, iRow>(context, std::make_index_sequence<columns>()), ...); } template< template<size_t ix_, size_t iy_> typename Functor, size_t width, size_t height, typename FunctorContext> void Repeat(FunctorContext* context) { RepeatImpl<Functor, width>( context, std::make_index_sequence<height>()); } template<size_t ix, size_t iy> struct Init2dArrayFunctor { template<typename T> static void Execute(T* array) { array[iy][ix] = 10; } }; int main(int, const char**) { constexpr size_t w = 10; constexpr size_t h = 10; int array[w][h] { 0 }; Repeat<Init2dArrayFunctor, w, h>(array); for(size_t iy = 0; iy < h; ++iy) { for(size_t ix = 0; ix < w; ++ix) { std::cout << array[iy][ix] << ' '; } std::cout << std::endl; } return 0; }
But this method greatly complicates the reading of the code. Is it possible to do this trick with two folds on the same line?