You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将参数包中的可调用对象匹配到数组对应元素并传入额外参数?

问题描述

我有如下代码:

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 05:55:23