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
相关产品推荐
相关产品推荐

