如何将参数包中的可调用对象匹配到数组对应元素并传入额外参数?
问题描述
我有如下代码:
template<typename ...FunctionTypes> static void MainFunction(FunctionTypes... functions) { constexpr Uint32_t NumFunctions= sizeof...(FunctionTypes); std::array<double, NumFunctions> myArray; double arg1 = 4.2; int arg2= 9; for_each_tuple(myArray, FigureOutThisPart(myFunctions, arg1, arg2)...); }
其中for_each_tuple接收一个大小为N的元组或数组,以及N个用于处理每个元组元素的函数,该函数已实现,定义如下:
namespace detail { template <typename Tuple, std::size_t ...Indices, typename ...FunctionTypes> constexpr void for_each_tuple_impl(Tuple&& tuple, std::index_sequence<Indices...>, FunctionTypes&&... functionsIn) { std::tuple<FunctionTypes...> functions = std::tie(functionsIn...); using swallow = int[]; (void)swallow{ 1, // Make sure array has at least one element (std::get<Indices>(functions)(std::get<Indices>(std::forward<Tuple>(tuple))), void(), int{})... }; } } template <typename Tuple, typename ...Functions> void for_each_tuple(Tuple&& tuple, Functions&&... f) { constexpr std::size_t N = std::tuple_size<std::remove_reference_t<Tuple>>::value; static_assert(N == sizeof...(Functions), "Need one function per tuple entry"); detail::for_each_tuple_impl( std::forward<Tuple>(tuple), std::make_index_sequence<N>{}, std::forward<Functions>(f)...); }
我的需求是:一组myFunctions中的每个函数分别操作myArray的不同元素,且每个函数需要接收arg1、arg2和当前数组元素作为参数。希望找到合理的实现方式,且最好能是constexpr以在编译期解析。
解决方案
核心思路
for_each_tuple要求传入的处理函数仅接收数组/元组的当前元素作为参数,我们可以用lambda表达式包装原始函数,将arg1、arg2捕获到lambda内部,同时让lambda接收当前数组元素,以此适配for_each_tuple的接口要求。
实现代码
修改MainFunction的调用逻辑,用lambda包装每个传入的函数:
template<typename ...FunctionTypes> constexpr void MainFunction(FunctionTypes... functions) { constexpr Uint32_t NumFunctions = sizeof...(FunctionTypes); std::array<double, NumFunctions> myArray{}; // 显式初始化避免未定义行为 constexpr double arg1 = 4.2; // 改为constexpr支持编译期处理 constexpr int arg2 = 9; // 用lambda包装每个函数,捕获arg1、arg2,接收当前数组元素 for_each_tuple(myArray, [arg1, arg2, func = std::forward<FunctionTypes>(functions)] (double& elem) constexpr { func(arg1, arg2, elem); }... ); }
编译期constexpr适配要点
要让整个流程支持编译期解析,需满足以下条件:
arg1、arg2必须是constexpr(或编译期可确定的值)- 传入的
functions必须是constexpr函数/可调用对象 myArray需用编译期合法的方式初始化(比如{})- lambda表达式需添加
constexpr修饰(C++20及以上支持)
验证示例
假设我们有两个测试用的constexpr函数:
constexpr void func1(double a, int b, double& elem) { elem = a + b; } constexpr void func2(double a, int b, double& elem) { elem = a * b; }
调用MainFunction(func1, func2)后,编译期即可计算出myArray的元素值为[13.2, 37.8]。
原for_each_tuple的优化(可选)
用C++17的折叠表达式替代旧的swallow数组写法,让代码更简洁且完全支持constexpr:
namespace detail { template <typename Tuple, std::size_t ...Indices, typename ...FunctionTypes> constexpr void for_each_tuple_impl(Tuple&& tuple, std::index_sequence<Indices...>, FunctionTypes&&... functionsIn) { // 折叠表达式替代swallow数组,代码更简洁 (std::get<Indices>(std::tie(functionsIn...))(std::get<Indices>(std::forward<Tuple>(tuple))), ...); } } template <typename Tuple, typename ...Functions> constexpr void for_each_tuple(Tuple&& tuple, Functions&&... f) { constexpr std::size_t N = std::tuple_size_v<std::remove_reference_t<Tuple>>; static_assert(N == sizeof...(Functions), "Need one function per tuple entry"); detail::for_each_tuple_impl( std::forward<Tuple>(tuple), std::make_index_sequence<N>{}, std::forward<Functions>(f)...); }
内容的提问来源于stack exchange,提问作者Danny
相关产品推荐
相关产品推荐

