C++17:模板替换时如何检查前N个构造参数为整数类型?
C++17模板类构造函数:前N个参数的整数类型SFINAE检查
我在C++17中编写模板类构造函数时,需要确保前N个参数为整数类型,且检查必须在模板替换阶段完成(不符合条件的构造函数不能存在,函数体内的static_assert无法满足该需求)。由于是类的构造函数,需通过模板参数实现SFINAE。
现有可行场景
- 当N为固定值(如N=2)时,可直接显式声明前N个参数并检查:
struct A { template<class Arg1, class Arg2, class... OtherArgs, std::enable_if_t<(std::is_integral_v<Arg1> && std::is_integral_v<Arg2>), int> = 0 > A(Arg1 arg1, Arg2 arg2, OtherArgs... otherArgs) {} };
- 若要检查所有参数均为整数类型,代码如下:
template<std::size_t N> struct A { template<class... Args, std::enable_if_t<std::conjunction_v<std::is_integral<Args>...>, int> = 0 > A(Args... args) {} };
需求与疑问
是否存在类似INDEX_OF的工具,能获取参数包中参数的索引,从而仅检查前N个参数是否为整数?期望的代码结构大致如下:
template<std::size_t N> struct A { template<class... Args, std::enable_if_t<std::conjunction_v< std::disjunction< std::bool_constant< (INDEX_OF(Args) >= N) >, std::is_integral<Args> >... >, int> = 0 > A(Args... args) {} };
解决方案:利用索引序列与类型提取实现
C++17没有直接的INDEX_OF工具,但可以通过参数包索引展开结合标准库模板实现需求。核心思路是生成0到N-1的索引序列,逐一检查这些位置的参数是否为整数类型。
完整实现代码
#include <type_traits> #include <tuple> #include <utility> template <std::size_t N> struct A { // 辅助函数模板:检查前N个参数是否为整数类型 template <typename... Args, std::size_t... Is> static constexpr bool check_first_n(std::index_sequence<Is...>) { // 折叠表达式:检查每个索引对应的参数是否为整数 return (... && std::is_integral_v<std::tuple_element_t<Is, std::tuple<Args...>>>); } template <typename... Args, std::enable_if_t< (sizeof...(Args) >= N) && // 确保参数数量至少为N,避免索引越界 check_first_n<Args...>(std::make_index_sequence<N>{}), int> = 0> A(Args... args) {} };
代码说明
- 索引序列生成:
std::make_index_sequence<N>会生成一个包含0到N-1的编译期整数序列,用于定位前N个参数。 - 类型提取与检查:
std::tuple_element_t<Is, std::tuple<Args...>>从参数包中提取对应索引的类型,再通过std::is_integral_v判断是否为整数类型。 - 折叠表达式验证:
(... && ...)将所有前N个参数的检查结果做逻辑与,确保全部满足整数类型要求。 - 参数数量校验:
sizeof...(Args) >= N避免参数数量不足时出现索引越界的编译错误。
测试示例
// 合法:前2个参数为整数 A<2> a1(1, 2, "hello world"); // 合法:前3个参数为整数 A<3> a2(10, 20, 30); // 编译错误:第一个参数是浮点数,不符合要求 // A<2> a3(1.5, 2, "error"); // 编译错误:第三个参数是字符串,不符合要求 // A<3> a4(1, 2, "3");
内容的提问来源于stack exchange,提问作者tmlen
相关产品推荐
相关产品推荐

