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

非递归实现多源tuple元素赋值至预创建目标tuple的技术问题

解决方案:非递归实现多源Tuple元素赋值到预创建目标Tuple

要解决代码中???的替换问题,核心是编译时计算每个源Tuple在目标Tuple中的起始偏移量(即前面所有源Tuple的元素总数之和),然后通过折叠表达式展开赋值操作。以下是两种兼容不同C++版本的非递归实现方案:

方案1:C++20 简洁实现(推荐)

利用C++20的lambda模板参数特性,直接在函数内完成编译时偏移计算与赋值展开:

#include <tuple>
#include <array>
#include <utility>
#include <cassert>

template<std::size_t from_element, typename dstT, typename srcTs, std::size_t... Is>
void assign_elms(dstT& dst, const srcTs& src, std::index_sequence<Is...>) {
    ((std::get<from_element + Is>(dst) = std::get<Is>(src)), ...);
}

template<std::size_t from_element, typename dstT, typename srcT>
void assign_impl(dstT& dst, const srcT& src) {
    assign_elms<from_element>(dst, src, std::make_index_sequence<std::tuple_size_v<srcT>>());
}

template<typename dstT, typename... srcTs>
void assign(dstT& dst, const srcTs&... srcs) {
    // 编译时获取每个源Tuple的元素数量
    constexpr std::array src_sizes = {std::tuple_size_v<srcTs>...};
    // 编译时生成每个源Tuple的起始偏移量(前缀和)
    constexpr auto prefix_offsets = []{
        std::array<std::size_t, sizeof...(srcTs)> offsets{};
        std::size_t current_offset = 0;
        for(std::size_t i = 0; i < sizeof...(srcTs); ++i) {
            offsets[i] = current_offset;
            current_offset += src_sizes[i];
        }
        return offsets;
    }();

    // 绑定偏移量与对应源Tuple,展开赋值操作
    auto apply_assignments = [&]<std::size_t... Is>(std::index_sequence<Is...>) {
        (assign_impl<prefix_offsets[Is]>(dst, std::get<Is>(std::tie(srcs...))), ...);
    };

    apply_assignments(std::index_sequence_for<srcTs...>());
}

template<typename... Ts>
using tuple_concat_t = decltype(std::tuple_cat(std::declval<Ts>()...));

int main() {
    std::tuple t1{ 1, 2.2f, 3.33 };
    std::tuple t2{ 4, 5.5f };
    std::tuple t3{ 6 };

    tuple_concat_t<decltype(t1), decltype(t2), decltype(t3)> tr;
    assign(tr, t1, t2, t3); 

    // 验证赋值结果
    static_assert(std::tuple_size_v<decltype(tr)> == 6);
    assert(std::get<0>(tr) == 1);
    assert(std::get<1>(tr) == 2.2f);
    assert(std::get<2>(tr) == 3.33);
    assert(std::get<3>(tr) == 4);
    assert(std::get<4>(tr) == 5.5f);
    assert(std::get<5>(tr) == 6);
}

方案2:C++17 兼容实现

如果需要兼容C++17(不支持lambda模板参数),可以通过辅助模板函数完成展开:

#include <tuple>
#include <array>
#include <utility>
#include <cassert>

template<std::size_t from_element, typename dstT, typename srcTs, std::size_t... Is>
void assign_elms(dstT& dst, const srcTs& src, std::index_sequence<Is...>) {
    ((std::get<from_element + Is>(dst) = std::get<Is>(src)), ...);
}

template<std::size_t from_element, typename dstT, typename srcT>
void assign_impl(dstT& dst, const srcT& src) {
    assign_elms<from_element>(dst, src, std::make_index_sequence<std::tuple_size_v<srcT>>());
}

// 辅助函数:绑定偏移量与源Tuple展开赋值
template<typename dstT, typename... srcTs, std::size_t... Is>
void assign_helper(dstT& dst, const std::tuple<srcTs...>& src_tuple, std::index_sequence<Is...>, const std::array<std::size_t, sizeof...(srcTs)>& offsets) {
    (assign_impl<offsets[Is]>(dst, std::get<Is>(src_tuple)), ...);
}

template<typename dstT, typename... srcTs>
void assign(dstT& dst, const srcTs&... srcs) {
    constexpr std::array src_sizes = {std::tuple_size_v<srcTs>...};
    constexpr auto prefix_offsets = []{
        std::array<std::size_t, sizeof...(srcTs)> offsets{};
        std::size_t current_offset = 0;
        for(std::size_t i = 0; i < sizeof...(srcTs); ++i) {
            offsets[i] = current_offset;
            current_offset += src_sizes[i];
        }
        return offsets;
    }();

    assign_helper(dst, std::tie(srcs...), std::index_sequence_for<srcTs...>(), prefix_offsets);
}

template<typename... Ts>
using tuple_concat_t = decltype(std::tuple_cat(std::declval<Ts>()...));

int main() {
    std::tuple t1{ 1, 2.2f, 3.33 };
    std::tuple t2{ 4, 5.5f };
    std::tuple t3{ 6 };

    tuple_concat_t<decltype(t1), decltype(t2), decltype(t3)> tr;
    assign(tr, t1, t2, t3); 

    // 验证赋值结果
    static_assert(std::tuple_size_v<decltype(tr)> == 6);
    assert(std::get<0>(tr) == 1);
    assert(std::get<1>(tr) == 2.2f);
    assert(std::get<2>(tr) == 3.33);
    assert(std::get<3>(tr) == 4);
    assert(std::get<4>(tr) == 5.5f);
    assert(std::get<5>(tr) == 6);
}

核心逻辑说明

  1. 编译时计算源Tuple大小:通过std::tuple_size_v获取每个源Tuple的元素数量,存入编译时常量数组。
  2. 生成前缀和偏移量:用constexpr lambda计算每个源Tuple在目标Tuple中的起始位置(第一个源从0开始,后续源的起始位置为前面所有源的元素总数之和)。
  3. 展开赋值操作:利用std::index_sequence_for生成源Tuple的索引序列,将每个源Tuple与对应的偏移量绑定,调用assign_impl完成元素赋值。

内容的提问来源于stack exchange,提问作者Konstantin Makarov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 10:23:15