一种制作apply_on_each() 的方法,该apply_on_each() 接收一个接收未定义数量的通用参数并调用它们(部分)以 C++17 方式展开的 lambda(或函数)。
说实话,这只是对 Bolov 巫毒答案的概括。
首先,一组constexpr函数来检测一个函数的参数个数(假设参数是通用的,所以假设一个整数零列表是可以接受的)
template <typename F, typename ... Ts>
constexpr auto numArgsH (int, Ts ... ts)
-> decltype( std::declval<F>()(ts...), std::size_t{} )
{ return sizeof...(Ts); }
template <typename F, typename ... Ts>
constexpr auto numArgsH (long, Ts ... ts)
{ return numArgsH<F>(0, 0, ts...); }
template <typename F>
constexpr auto numArgs ()
{ return numArgsH<F>(0); }
现在 apply_on_each() 函数检测函数 func 的参数数量,并按照 Bolov 的示例调用(第一个)辅助函数,添加一个(双精度,在此泛化中)索引列表和 @ 987654326@ 个参数
template <typename F, typename ... Ts>
void apply_on_each (F func, Ts ... ts)
{
static constexpr auto num_args { numArgs<F>() };
apply_on_each_h1(func,
std::make_index_sequence<sizeof...(Ts)/num_args>{},
std::make_index_sequence<num_args>{},
std::make_tuple(ts...));
}
现在第一个辅助函数“解包”第一个索引序列,使用 C++17 折叠,并调用第二个辅助函数
template <typename F, std::size_t ... Is, std::size_t ... Js,
typename ... Ts>
void apply_on_each_h1 (F func,
std::index_sequence<Is...> const &,
std::index_sequence<Js...> const & js,
std::tuple<Ts...> const & t)
{ (apply_on_each_h2<Is>(func, js, t), ...) ; }
现在是使用索引的最后一个辅助函数,使用正确的参数调用 func
template <std::size_t I, typename F, std::size_t ... Js, typename ... Ts>
void apply_on_each_h2 (F func,
std::index_sequence<Js...> const & js,
std::tuple<Ts...> const & t)
{ func(std::get<I*sizeof...(Js)+Js>(t)...); }
以下是一个完整的例子
#include <tuple>
#include <utility>
#include <iostream>
#include <type_traits>
template <typename F, typename ... Ts>
constexpr auto numArgsH (int, Ts ... ts)
-> decltype( std::declval<F>()(ts...), std::size_t{} )
{ return sizeof...(Ts); }
template <typename F, typename ... Ts>
constexpr auto numArgsH (long, Ts ... ts)
{ return numArgsH<F>(0, 0, ts...); }
template <typename F>
constexpr auto numArgs ()
{ return numArgsH<F>(0); }
template <std::size_t I, typename F, std::size_t ... Js, typename ... Ts>
void apply_on_each_h2 (F func,
std::index_sequence<Js...> const & js,
std::tuple<Ts...> const & t)
{ func(std::get<I*sizeof...(Js)+Js>(t)...); }
template <typename F, std::size_t ... Is, std::size_t ... Js,
typename ... Ts>
void apply_on_each_h1 (F func,
std::index_sequence<Is...> const &,
std::index_sequence<Js...> const & js,
std::tuple<Ts...> const & t)
{ (apply_on_each_h2<Is>(func, js, t), ...) ; }
template <typename F, typename ... Ts>
void apply_on_each (F func, Ts ... ts)
{
static constexpr auto num_args { numArgs<F>() };
apply_on_each_h1(func,
std::make_index_sequence<sizeof...(Ts)/num_args>{},
std::make_index_sequence<num_args>{},
std::make_tuple(ts...));
}
int main()
{
auto l1 = [](auto a)
{ std::cout << "- l1:" << a << std::endl; };
auto l2 = [](auto a, auto b)
{ std::cout << "- l2:" << a << ", " << b << std::endl; };
auto l3 = [](auto a, auto b, auto c)
{ std::cout << "- l3:" << a << ", " << b << ", " << c << std::endl; };
apply_on_each(l1, 1, 2l, 3ll, "4", '5', 6.0);
apply_on_each(l2, 1, 2l, 3ll, "4", '5', 6.0);
apply_on_each(l3, 1, 2l, 3ll, "4", '5', 6.0);
}