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

如何使用Lambda遍历std::tuple索引并操作多组元组?

多元组按索引遍历执行元素级运算的多版本C++解决方案

针对你需要遍历多个同结构元组的对应索引元素、执行统一运算的需求,以下是不同C++版本下的优雅实现方案:


C++20及以上(支持模板Lambda)

C++20的模板Lambda和折叠表达式让这个需求的实现最简洁,不需要复杂的辅助模板:

方案1:通用索引遍历辅助函数

直接生成元组的索引序列,用折叠表达式展开每个索引的操作:

#include <tuple>
#include <utility>

template <typename Func, typename... Tuples>
void tuple_for_each_index(Func&& func, Tuples&&... tuples) {
    constexpr auto tuple_size = std::tuple_size_v<std::remove_reference_t<decltype(std::get<0>(std::forward_as_tuple(tuples...)))>>;
    // 用模板Lambda捕获索引序列
    [&]<std::size_t... Indices>(std::index_sequence<Indices...>) {
        // 折叠表达式逐个调用函数
        (func(std::get<Indices>(std::forward<Tuples>(tuples))...), ...);
    }(std::make_index_sequence<tuple_size>{});
}

使用示例(对应你的operator+=场景):

FSkyLightSettings& operator+=(FSkyLightSettings& Other)
{
    auto tup1 = AsTuple();
    auto tup2 = Other.AsTuple();

    tuple_for_each_index([](auto& elem1, auto& elem2) {
        *elem1 += *elem2; // 直接利用元素的+=运算符,无需显式指定索引
    }, tup1, tup2);

    return *this;
}

如果需要显式获取当前索引(比如做额外逻辑),可以修改辅助函数传递索引常量:

template <typename Func, typename... Tuples>
void tuple_for_each_index_with_idx(Func&& func, Tuples&&... tuples) {
    constexpr auto tuple_size = std::tuple_size_v<std::remove_reference_t<decltype(std::get<0>(std::forward_as_tuple(tuples...)))>>;
    [&]<std::size_t... Indices>(std::index_sequence<Indices...>) {
        (func(std::integral_constant<std::size_t, Indices>{}, std::get<Indices>(std::forward<Tuples>(tuples))...), ...);
    }(std::make_index_sequence<tuple_size>{});
}

使用时可以拿到索引值:

tuple_for_each_index_with_idx([](auto idx, auto& elem1, auto& elem2) {
    // idx.value() 即为当前元素的索引
    *elem1 += *elem2;
}, tup1, tup2);

方案2:修复你原有的代码逻辑

你之前尝试的递归Lambda遇到C3536错误,是因为Lambda未完成定义就递归调用自身。C++20里无需递归,直接用折叠表达式展开所有索引调用即可:

FSkyLightSettings& operator+=(FSkyLightSettings& Other)
{
    auto tup1 = AsTuple();
    auto tup2 = Other.AsTuple();
    using TupType = decltype(tup1);

    auto add_func = []<typename Tup, int Index>(Tup t1, Tup t2) {
        *t1.template Get<Index>() += *t2.template Get<Index>();
    };

    // 生成索引序列并折叠调用
    [&, add_func]<std::size_t... Indices>(std::index_sequence<Indices...>) {
        (add_func.template operator()<TupType, Indices>(tup1, tup2), ...);
    }(std::make_index_sequence<std::tuple_size_v<TupType>>{});

    return *this;
}

C++17版本(支持折叠表达式和std::index_sequence,无模板Lambda)

C++17没有模板Lambda,需要用普通函数模板替代:

通用辅助函数实现

#include <tuple>
#include <utility>

// 单索引操作函数
template <std::size_t Index, typename Func, typename... Tuples>
void apply_single_index(Func&& func, Tuples&&... tuples) {
    func(std::get<Index>(std::forward<Tuples>(tuples))...);
}

// 索引序列展开实现
template <typename Func, typename... Tuples, std::size_t... Indices>
void tuple_for_each_index_impl(Func&& func, std::index_sequence<Indices...>, Tuples&&... tuples) {
    (apply_single_index<Indices>(std::forward<Func>(func), std::forward<Tuples>(tuples)...), ...);
}

// 对外接口
template <typename Func, typename... Tuples>
void tuple_for_each_index(Func&& func, Tuples&&... tuples) {
    constexpr auto tuple_size = std::tuple_size_v<std::remove_reference_t<decltype(std::get<0>(std::forward_as_tuple(tuples...)))>>;
    tuple_for_each_index_impl(std::forward<Func>(func), std::make_index_sequence<tuple_size>{}, std::forward<Tuples>(tuples)...);
}

使用示例:

FSkyLightSettings& operator+=(FSkyLightSettings& Other)
{
    auto tup1 = AsTuple();
    auto tup2 = Other.AsTuple();

    tuple_for_each_index([](auto& elem1, auto& elem2) {
        *elem1 += *elem2;
    }, tup1, tup2);

    return *this;
}

若需要索引,修改apply_single_index传递索引常量即可:

template <std::size_t Index, typename Func, typename... Tuples>
void apply_single_index(Func&& func, Tuples&&... tuples) {
    func(std::integral_constant<std::size_t, Index>{}, std::get<Index>(std::forward<Tuples>(tuples))...);
}

C11/C14版本(无折叠表达式,需递归模板展开)

这两个版本没有折叠表达式,只能通过递归模板来遍历索引:

通用辅助函数实现

#include <tuple>
#include <utility>

// 递归终止条件:索引等于元组大小时停止
template <std::size_t Index, typename Func, typename... Tuples>
typename std::enable_if_t<Index == std::tuple_size_v<std::remove_reference_t<decltype(std::get<0>(std::forward_as_tuple(tuples...)))>>>
tuple_for_each_index_impl(Func&&, Tuples&&...) {}

// 递归展开:处理当前索引后,递归处理下一个索引
template <std::size_t Index, typename Func, typename... Tuples>
typename std::enable_if_t<Index < std::tuple_size_v<std::remove_reference_t<decltype(std::get<0>(std::forward_as_tuple(tuples...)))>>>
tuple_for_each_index_impl(Func&& func, Tuples&&... tuples) {
    func(std::get<Index>(std::forward<Tuples>(tuples))...);
    tuple_for_each_index_impl<Index + 1>(std::forward<Func>(func), std::forward<Tuples>(tuples)...);
}

// 对外接口:从索引0开始递归
template <typename Func, typename... Tuples>
void tuple_for_each_index(Func&& func, Tuples&&... tuples) {
    tuple_for_each_index_impl<0>(std::forward<Func>(func), std::forward<Tuples>(tuples)...);
}

使用示例:

FSkyLightSettings& operator+=(FSkyLightSettings& Other)
{
    auto tup1 = AsTuple();
    auto tup2 = Other.AsTuple();

    tuple_for_each_index([](auto& elem1, auto& elem2) {
        *elem1 += *elem2;
    }, tup1, tup2);

    return *this;
}

需要索引的话,修改递归函数传递std::integral_constant即可。


内容的提问来源于stack exchange,提问作者Artem Selivanov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 09:26:17