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

如何避免递归,以类std::views方式对参数包过滤生成std::tuple?

参数包类型过滤的非递归实现方案

问题描述

我有时需要从给定的参数包中过滤某些类型,并将结果以std::tuple形式返回,例如可基于类型在参数包中的索引进行过滤。

以下是一个类步长过滤的递归实现示例,其语义与std::views::stride类似:

#include <tuple>

namespace pack
{
    template<int R, int IDX, typename...ARGS>
    struct stride_impl  { };

    template<int R, int IDX, typename...ARGS>
    using stride_impl_t = typename stride_impl<R,IDX,ARGS...>::type;

    template<int R, int IDX, typename T, typename...ARGS>
    struct stride_impl<R,IDX,T,ARGS...>
    {
        using type = std::conditional_t <
            IDX%R==0,
            decltype(std::tuple_cat (
                std::tuple<T> {}, 
                stride_impl_t<R,IDX+1,ARGS...> {} 
            )),
            stride_impl_t<R,IDX+1,ARGS...>
        >;     
    };

    template<int R, int IDX>
    struct stride_impl<R,IDX>  {  using type = std::tuple<>;  };

    template<int R, typename...ARGS>
    struct stride 
    {  
        static_assert(R>0);
        using type = stride_impl_t<R,0,ARGS...>;
    };

    template<int R, typename ...ARGS>
    using stride_t = typename stride<R,ARGS...>::type;
};

template<int R> using example = pack::stride_t<R,char,int,long,float,double>;

static_assert (std::is_same_v< example<1>, std::tuple<char,int,long,float,double>>);
static_assert (std::is_same_v< example<2>, std::tuple<char,    long,      double>>);
static_assert (std::is_same_v< example<3>, std::tuple<char,         float       >>);
static_assert (std::is_same_v< example<4>, std::tuple<char,               double>>);
static_assert (std::is_same_v< example<5>, std::tuple<char                      >>);

int main() {}

该递归实现较为繁琐,请问是否存在无需显式递归的更直接实现方式(例如使用折叠表达式)?或者标准库中是否有类似std::views的工具可用于此类参数包过滤?


解决方案

方法一:利用索引序列+折叠表达式实现

借助std::index_sequence生成参数包的索引,通过折叠表达式完成条件筛选与tuple拼接,完全避免显式递归:

#include <tuple>
#include <utility>
#include <type_traits>

namespace pack
{
    template<int R, typename... Args>
    using stride_t = decltype([]<std::size_t... Idx>(std::index_sequence<Idx...>) {
        return std::tuple_cat(
            // 对每个索引判断是否符合步长条件,符合则保留该类型的tuple,否则为空tuple
            std::declval<std::conditional_t<Idx % R == 0, std::tuple<Args>, std::tuple<>>>()...
        );
    }(std::index_sequence_for<Args...>{}));
}

template<int R> using example = pack::stride_t<R, char, int, long, float, double>;

// 验证结果正确性
static_assert(std::is_same_v<example<1>, std::tuple<char, int, long, float, double>>);
static_assert(std::is_same_v<example<2>, std::tuple<char, long, double>>);
static_assert(std::is_same_v<example<3>, std::tuple<char, float>>);
static_assert(std::is_same_v<example<4>, std::tuple<char, double>>);
static_assert(std::is_same_v<example<5>, std::tuple<char>>);

int main() {}

这个方案的核心是:

  • 用std::index_sequence_for自动生成与参数包长度匹配的索引序列
  • 通过C++20模板lambda捕获索引序列,结合折叠表达式一次性完成所有类型的条件判断与tuple拼接

方法二:简化版无lambda实现(兼容C++17)

如果需要兼容C++17,可以用辅助函数替代模板lambda,同样避免显式递归:

#include <tuple>
#include <utility>
#include <type_traits>

namespace pack
{
    template<int R, typename... Args, std::size_t... Idx>
    auto stride_helper(std::index_sequence<Idx...>) 
        -> decltype(std::tuple_cat(
            std::declval<std::conditional_t<Idx % R == 0, std::tuple<Args>, std::tuple<>>>()...
        ));

    template<int R, typename... Args>
    using stride_t = decltype(stride_helper<R, Args...>(std::index_sequence_for<Args...>{}));
}

template<int R> using example = pack::stride_t<R, char, int, long, float, double>;

// 验证同前
static_assert(std::is_same_v<example<1>, std::tuple<char, int, long, float, double>>);
static_assert(std::is_same_v<example<2>, std::tuple<char, long, double>>);
static_assert(std::is_same_v<example<3>, std::tuple<char, float>>);
static_assert(std::is_same_v<example<4>, std::tuple<char, double>>);
static_assert(std::is_same_v<example<5>, std::tuple<char>>);

int main() {}

标准库工具说明

标准库中没有直接针对编译期参数包的过滤视图工具,std::views::stride仅适用于运行时范围。但C++17及以后的元编程特性(折叠表达式、std::index_sequence)已经能大幅简化这类编译期类型过滤的实现,无需依赖额外库。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 04:25:54