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

C++17下实现std::tuple类型映射的问题求助

问题:std::tuple类型间顺序映射的编译错误与修正

需求与逻辑

  • 实现两种std::tuple类型间的转换:类型相同则建立映射,重复类型按输入序列的先后顺序匹配输出序列的对应项,最终需确保所有输出类型都被成功映射。
  • 核心匹配逻辑:

while 存在未处理的<input, output>对
如果当前输入类型 == 当前输出类型
记录映射关系,同时推进输入、输出序列到下一项
否则
仅推进输入序列到下一项
断言:所有输出类型均已完成映射

当前实现与错误

现有代码

template <auto> struct value {};
template <auto... Vals> struct value_sequence {};
template <class... Vals> struct placeholder {};

template <auto... As, auto... Bs>
constexpr value_sequence<As..., Bs...> operator+(value_sequence<As...>, value_sequence<Bs...>)
{
    return {};
}

template <size_t Idx, size_t... Idxs, size_t OtherIdx, size_t... OtherIdxs, class T, class... Ts, class OtherT, class... OtherTs>
constexpr auto mapper(const std::index_sequence<Idx, Idxs...>&, const std::index_sequence<OtherIdx, OtherIdxs...>&, const placeholder<T, Ts...>&,
                      const placeholder<OtherT, OtherTs...>&)
{
    if constexpr (sizeof...(OtherIdxs) == 0)
    {
        static_assert(std::is_same_v<T, OtherT>);
        return value_sequence<Idx>{};
    }
    else if constexpr (std::is_same_v<T, OtherT>)
    {
        return value_sequence<Idx>{} +
               mapper(std::index_sequence<Idxs...>{}, std::index_sequence<OtherIdxs...>{}, placeholder<Ts...>{}, placeholder<OtherTs...>{});
    }
    else
    {
        return mapper(std::index_sequence<Idx, Idxs...>{}, std::index_sequence<OtherIdxs...>{}, placeholder<T, Ts...>{}, placeholder<OtherTs...>{});
    }
}

调用方式

mapper(std::make_index_sequence<sizeof...(Ts)>{}, std::make_index_sequence<sizeof...(OtherTs)>{},
                                                placeholder<Ts...>{}, placeholder<OtherTs...>{})

编译错误

error C2672: 'mapper': no matching overloaded function found,指向else if分支的递归调用。

问题分析与修正

核心问题

  1. 递归逻辑错误:原代码中类型不匹配时,错误地推进了输出序列而非输入序列,完全违背需求逻辑。
  2. 缺少空序列重载:原模板仅接受非空的std::index_sequence作为参数,当输入序列被推进至空时,无匹配的重载函数,导致编译失败。
  3. 边界处理不完善:未处理输出序列已完成映射(为空)的终止条件,以及输入耗尽但输出未完成的断言场景。

修正后的完整代码

#include <tuple>
#include <utility>

template <auto> struct value {};
template <auto... Vals> struct value_sequence {};
template <class... Vals> struct placeholder {};

// 合并两个value_sequence
template <auto... As, auto... Bs>
constexpr value_sequence<As..., Bs...> operator+(value_sequence<As...>, value_sequence<Bs...>)
{
    return {};
}

// 终止条件1:输出序列已全部映射完成
template <size_t... Idxs, class... Ts>
constexpr auto mapper(const std::index_sequence<Idxs...>&, const std::index_sequence<>&, const placeholder<Ts...>&,
                      const placeholder<>&)
{
    return value_sequence<>{};
}

// 终止条件2:输入序列耗尽但输出未完成,触发断言
template <size_t... OtherIdxs, class... OtherTs>
constexpr auto mapper(const std::index_sequence<>&, const std::index_sequence<OtherIdxs...>&, const placeholder<>&,
                      const placeholder<OtherTs...>&)
{
    static_assert(sizeof...(OtherIdxs) == 0, "Input sequence exhausted before all output types are mapped");
    return value_sequence<>{};
}

// 主递归逻辑
template <size_t Idx, size_t... Idxs, size_t OtherIdx, size_t... OtherIdxs, class T, class... Ts, class OtherT, class... OtherTs>
constexpr auto mapper(const std::index_sequence<Idx, Idxs...>&, const std::index_sequence<OtherIdx, OtherIdxs...>&, const placeholder<T, Ts...>&,
                      const placeholder<OtherT, OtherTs...>&)
{
    if constexpr (std::is_same_v<T, OtherT>)
    {
        // 类型匹配:记录输入索引,同时推进两个序列
        return value_sequence<Idx>{} +
               mapper(std::index_sequence<Idxs...>{}, std::index_sequence<OtherIdxs...>{}, placeholder<Ts...>{}, placeholder<OtherTs...>{});
    }
    else
    {
        // 类型不匹配:仅推进输入序列,输出序列保持当前位置
        return mapper(std::index_sequence<Idxs...>{}, std::index_sequence<OtherIdx, OtherIdxs...>{}, placeholder<Ts...>{}, placeholder<OtherT, OtherTs...>{});
    }
}

测试示例

// 输入tuple:int, float, int, double;输出tuple:int, double
using InputTuple = std::tuple<int, float, int, double>;
using OutputTuple = std::tuple<int, double>;

constexpr auto mapping = mapper(
    std::make_index_sequence<std::tuple_size_v<InputTuple>>{},
    std::make_index_sequence<std::tuple_size_v<OutputTuple>>{},
    placeholder<std::tuple_element_t<0, InputTuple>,
                std::tuple_element_t<1, InputTuple>,
                std::tuple_element_t<2, InputTuple>,
                std::tuple_element_t<3, InputTuple>>{},
    placeholder<std::tuple_element_t<0, OutputTuple>,
                std::tuple_element_t<1, OutputTuple>>{}
);
// mapping 类型为 value_sequence<0, 3>,对应输入的第1个int和第4个double

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 10:17:23