You use C++14 so you can use std::index_sequence/std::make_index_sequence/std::index_sequence_for...
I propose to call product() passing first the function and next the vectors.
I mean
product([=](int i, double j, int k) { process(i, j, k); }, iv, jv, kv);
This way you can use variadic templates for vectors.
I propose also the following helper functions
template <typename F, std::size_t ... Is, typename Tp>
void productH (F f, std::index_sequence<Is...> const &, Tp const & tp)
{ f(std::get<Is>(tp)...); }
template <typename F, typename Is, typename Tp, typename T0, typename ... Ts>
void productH (F f, Is const & is, Tp const & tp, T0 const & t0, Ts ... ts)
{
for ( auto const & val : t0 )
productH(f, is, std::tuple_cat(tp, std::tie(val)), ts...);
}
so product() simply become
template <typename F, typename ... Ts>
void product (F f, Ts ... ts)
{ productH(f, std::index_sequence_for<Ts...>{}, std::make_tuple(), ts...); }
The idea is extract and accumulate in a std::tuple the values. Given the final std::tuple, call the function extracting the values from the std::tuple using std::get and the indexes generated with std::index_sequence_for.
Observe that there is no need that vector are std::vectors; the can be std::queue, std::array, etc.
The following is a full compiling example
#include <array>
#include <tuple>
#include <deque>
#include <vector>
#include <utility>
#include <iostream>
template <typename F, std::size_t ... Is, typename Tp>
void productH (F f, std::index_sequence<Is...> const &, Tp const & tp)
{ f(std::get<Is>(tp)...); }
template <typename F, typename Is, typename Tp, typename T0, typename ... Ts>
void productH (F f, Is const & is, Tp const & tp, T0 const & t0, Ts ... ts)
{
for ( auto const & val : t0 )
productH(f, is, std::tuple_cat(tp, std::tie(val)), ts...);
}
template <typename F, typename ... Ts>
void product (F f, Ts ... ts)
{ productH(f, std::index_sequence_for<Ts...>{}, std::make_tuple(), ts...); }
void process (int i1, double d1, int i2)
{ std::cout << '[' << i1 << ',' << d1 << ',' << i2 << ']' << std::endl; }
int main ()
{
std::vector<int> iv = { 1, 2, 3, 4 };
std::array<double, 4u> jv = { { .5, 1., 1.5, 2. } };
std::deque<int> kv = { 5, 4, 3, 2 };
product([=](int i, double j, int k) { process(i, j, k); }, iv, jv, kv);
}
Unfortunately you can't use C++17 where you can avoid the std::index_sequence/std::index_sequence_for/std::get() part and use std::apply() as follows
template <typename F, typename Tp>
void productH (F f, Tp const & tp)
{ std::apply(f, tp); }
template <typename F, typename Tp, typename T0, typename ... Ts>
void productH (F f, Tp const & tp, T0 const & t0, Ts ... ts)
{
for ( auto const & val : t0 )
productH(f, std::tuple_cat(tp, std::tie(val)), ts...);
}
template <typename F, typename ... Ts>
void product (F f, Ts ... ts)
{ productH(f, std::make_tuple(), ts...); }