You need to enable JavaScript to run this app. C++如何从可变模板参数生成函数模板特化并限制合法调用
优惠活动
大模型
产品
解决方案
定价
更多

C++如何从可变模板参数生成函数模板特化并限制合法调用

实现方案

完整可运行代码(C++17及以上版本)

#include <array>
#include <type_traits>

template<typename T_, size_t size_>
struct arg
{
    using T = T_;
    static constexpr size_t size = size_;
};

// 编译期工具:判断类型T是否存在于Args参数包中
template<typename T, typename... Args>
constexpr bool type_in_pack_v = (... || std::is_same_v<T, Args>);

template<typename... Arguments>
struct Foo
{
    template<typename Argument>
    std::array<typename Argument::T, Argument::size>& getArray()
    {
        // 编译期校验传入类型是否在Foo的参数包范围内
        static_assert(type_in_pack_v<Argument, Arguments...>, 
                      "传入的Argument类型不在Foo的模板参数列表中");
        static std::array<typename Argument::T, Argument::size> arr;
        return arr;
    }
};

int main()
{
    Foo<arg<int, 10>, arg<float, 10>, arg<float, 1>> myFoo;
    myFoo.getArray<arg<int, 10>>(); // 正常返回对应array实例
    myFoo.getArray<arg<float, 10>>(); // 返回独立的另一个array实例
    // 下行代码编译失败,触发static_assert错误
    // myFoo.getArray<arg<bool, 1>>(); 
}

实现逻辑说明

  • 类型存在性检查:通过C++17折叠表达式实现的type_in_pack_v编译期常量,会遍历Foo的所有可变模板参数,判断传入的Argument是否和参数包中的某一个类型完全匹配。
  • 非法调用拦截:static_assert会在编译阶段执行检查,如果传入的类型不在参数包范围内,直接终止编译并输出自定义错误信息,符合编译失败的需求。
  • 独立实例保证:模板函数的每个不同模板参数都会生成独立的函数实例,每个实例内部的静态变量arr互相独立,因此不同arg类型调用getArray会返回不同的array实例,完全满足需求。

C++11/14兼容版本(替换type_in_pack实现即可)

如果需要适配旧版本标准,可以用递归模板替换折叠表达式实现:

template<typename T, typename... Args>
struct type_in_pack : std::false_type {};

template<typename T, typename First, typename... Rest>
struct type_in_pack<T, First, Rest...> : 
    std::conditional<std::is_same<T, First>::value, 
                     std::true_type, 
                     type_in_pack<T, Rest...>>::type {};

template<typename T, typename... Args>
constexpr bool type_in_pack_v = type_in_pack<T, Args...>::value;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 01:30:03