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

如何减少递归可变参数继承的代码膨胀?

解决可变参数模板Base的代码膨胀问题

针对你遇到的Base<A,B,C>和Base<A,C,B>生成重复代码的问题,核心解决方案是对模板参数进行编译期标准化(排序+去重),让不同顺序的参数列表映射到同一个实例化类型,从而避免冗余代码生成。

实现思路

  1. 编译期对传入的类型参数列表进行去重,避免重复类型导致的冗余继承。
  2. 对去重后的类型列表按固定规则排序(比如基于std::type_index的比较),确保不同顺序的输入最终得到完全一致的参数序列。
  3. 修改Base模板,让它继承标准化后的参数序列对应的Base实例,这样无论输入参数顺序如何,编译器只会生成一份代码。

完整代码实现

第一步:实现编译期元工具(去重、排序、Tuple操作)

#include <type_traits>
#include <tuple>
#include <typeindex>
#include <iostream>
#include <memory>

// 辅助判断:类型T的type_index是否小于U
template<typename T, typename U>
constexpr bool type_less() {
    return std::type_index(typeid(T)) < std::type_index(typeid(U));
}

// 编译期Tuple截取前N个元素(C++17兼容)
template<std::size_t N, typename Tuple>
struct tuple_take;

template<std::size_t N, typename... Ts>
struct tuple_take<N, std::tuple<Ts...>> {
    using type = decltype(std::tuple_cat(
        std::declval<std::tuple<std::tuple_element_t<0, std::tuple<Ts...>>>>(),
        typename tuple_take<N-1, std::tuple<Ts...>>::type{}
    ));
};

template<typename... Ts>
struct tuple_take<0, std::tuple<Ts...>> {
    using type = std::tuple<>;
};

template<std::size_t N, typename Tuple>
using tuple_take_t = typename tuple_take<N, Tuple>::type;

// 编译期Tuple丢弃前N个元素(C++17兼容)
template<std::size_t N, typename Tuple>
struct tuple_drop;

template<std::size_t N, typename T, typename... Ts>
struct tuple_drop<N, std::tuple<T, Ts...>> {
    using type = typename tuple_drop<N-1, std::tuple<Ts...>>::type;
};

template<typename T, typename... Ts>
struct tuple_drop<0, std::tuple<T, Ts...>> {
    using type = std::tuple<T, Ts...>;
};

template<std::size_t N, typename Tuple>
using tuple_drop_t = typename tuple_drop<N, Tuple>::type;

// 编译期类型去重
template<typename... Ts>
struct unique_types;

template<>
struct unique_types<> {
    using type = std::tuple<>;
};

template<typename T, typename... Ts>
struct unique_types<T, Ts...> {
private:
    using rest_types = typename unique_types<Ts...>::type;
    static constexpr bool type_exists = (std::is_same_v<T, Ts> || ...);
public:
    using type = std::conditional_t<type_exists, 
                                   rest_types, 
                                   decltype(std::tuple_cat(std::make_tuple(std::declval<T>()), rest_types{}))>;
};

template<typename... Ts>
using unique_types_t = typename unique_types<Ts...>::type;

// 编译期类型排序(插入排序实现)
template<typename... Ts>
struct sorted_types;

template<>
struct sorted_types<> {
    using type = std::tuple<>;
};

// 将单个类型插入已排序的类型列表
template<typename T, typename... Ts>
struct insert_into_sorted {
private:
    using sorted_tuple = typename sorted_types<Ts...>::type;

    template<std::size_t I = 0, typename... Us>
    static constexpr std::size_t find_insert_pos(std::tuple<Us...>) {
        if constexpr (I == sizeof...(Us)) {
            return I;
        } else if constexpr (type_less<T, std::tuple_element_t<I, std::tuple<Us...>>>()) {
            return I;
        } else {
            return find_insert_pos<I+1>(std::tuple<Us...>{});
        }
    }

    static constexpr std::size_t insert_pos = find_insert_pos(sorted_tuple{});
public:
    using type = decltype(std::tuple_cat(
        tuple_take_t<insert_pos, sorted_tuple>{},
        std::make_tuple(std::declval<T>()),
        tuple_drop_t<insert_pos, sorted_tuple>{}
    ));
};

template<typename T, typename... Ts>
struct sorted_types<T, Ts...> {
    using type = typename insert_into_sorted<T, Ts...>::type;
};

// 从Tuple中提取类型列表,生成Base<Ts...>
template<typename Tuple>
struct tuple_to_base;

template<typename... Ts>
struct tuple_to_base<std::tuple<Ts...>> {
    using type = class Base<Ts...>;
};

template<typename Tuple>
using tuple_to_base_t = typename tuple_to_base<Tuple>::type;

第二步:修改Base模板,基于标准化参数列表实现

// 前置声明
template<typename... Ts>
class Base;

// 单参数Base特化(保留原有默认实现)
template<typename T>
class Base<T> {
public:
    virtual void visit(const T& t) const {
        // 默认实现:可按需修改
        std::cout << "Default implementation for type\n";
    }
};

// 多参数Base:先标准化参数,再继承
template<typename... Ts>
class Base : public tuple_to_base_t<typename sorted_types<typename unique_types<Ts...>::type>::type> {
public:
    // 导入所有visit重载
    using tuple_to_base_t<typename sorted_types<typename unique_types<Ts...>::type>::type>::visit;
};

第三步:验证你的使用场景

// 测试用结构体
struct A{};
struct B{};
struct C{};

// 自定义实现类
class Implementation: public Base<A,B,C> {
public:
    void visit(const A& a) const override {
        std::cout << "Special implementation for type A\n";
    }

    void visit(const B& b) const override {
        std::cout << "Special implementation for type B\n";
    }
    // C类使用默认实现
};

using BaseInterface = Base<A,B,C>;
void do_visit(const BaseInterface& v) {
    v.visit(A{});
    v.visit(B{});
    v.visit(C{});
}

int main() {
    // 验证不同参数顺序的Base是同一类型
    static_assert(std::is_same_v<Base<A,B,C>, Base<A,C,B>>, "Base instances should be same type");
    
    std::unique_ptr<BaseInterface> v = std::make_unique<Implementation>();
    do_visit(*v);
    
    return 0;
}

效果说明

  • 编译期会自动将Base<A,B,C>、Base<A,C,B>、Base<C,A,B>等所有排列组合,统一映射为同一个实例化类型(排序后的Base<A,B,C>),彻底消除冗余代码。
  • 支持自动去重,即使传入重复类型(如Base<A,A,B>),也会自动简化为Base<A,B>。
  • 完全兼容你原有的使用场景,自定义实现类无需修改,只需继承修改后的Base即可。

内容的提问来源于stack exchange,提问作者S.Li

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 13:50:25