能否在类定义中对非类型模板参数包使用enable_if?
问题描述
我希望实现一个模板类,接受任意数量的bool类型非类型模板参数,统计其中true的数量,并用这个数量作为基类Foo的模板参数实现继承。我写了一段伪代码,但无法编译,核心问题出在构造函数的bool... args并非正确展开的参数包。
伪代码如下:
template <int Dimensionality> struct Foo {}; // 要继承的基类 // 编译期统计bool参数中true数量的辅助结构体 template <bool B, bool... Args> struct count_true { static constexpr int value = count_true<B>::value + count_true<Args...>::value; }; template <> struct count_true<true> { static constexpr int value = 1; }; template <> struct count_true<false> { static constexpr int value = 0; }; // 想要实现的伪代码 template <bool... Args> struct Bar : public Foo<count_true<Args...>::value> { Bar(bool... args) { // 处理参数 static_assert(sizeof...(args) <= 1337); } };
解决方案
1. 修复编译期统计工具count_true
原递归实现缺失空参数包的特化,导致递归终止条件错误。推荐用C++17的折叠表达式简化实现,更简洁且不易出错:
#include <type_traits> #include <cassert> template <int Dimensionality> struct Foo {}; // 基类 // 编译期统计bool参数中true的数量 template <bool... Args> struct count_true { // 折叠表达式:将每个bool转为int后求和(true=1,false=0) static constexpr int value = (static_cast<int>(Args) + ...); };
如果需要兼容C++11/14,可补充空参数包特化修复递归逻辑:
template <bool... Args> struct count_true; // 空参数包特化:终止递归的基准条件 template <> struct count_true<> { static constexpr int value = 0; }; // 递归处理参数包 template <bool B, bool... Args> struct count_true<B, Args...> { static constexpr int value = count_true<B>::value + count_true<Args...>::value; }; // 单bool参数特化 template <> struct count_true<true> { static constexpr int value = 1; }; template <> struct count_true<false> { static constexpr int value = 0; };
2. 实现Bar类的正确写法
构造函数的核心需求是接收与模板参数数量匹配的bool参数,以下是两种可行实现:
写法一:初始化列表接收参数(C++11+)
通过初始化列表统一接收参数,配合编译期断言限制总数,运行时校验参数数量:
template <bool... Args> struct Bar : public Foo<count_true<Args...>::value> { Bar(std::initializer_list<bool> args) { // 编译期限制模板参数总数不超过1337 static_assert(sizeof...(Args) <= 1337, "模板参数数量超出上限"); // 运行时校验传入参数数量与模板参数一致 assert(args.size() == sizeof...(Args)); // 处理参数示例:遍历所有bool值 for (bool b : args) { // 添加你的业务逻辑 } } };
写法二:参数包展开+编译期强校验(C++17+)
通过enable_if确保所有参数都是bool类型,用static_assert强制参数数量与模板参数一致,完全在编译期完成校验:
template <bool... Args> struct Bar : public Foo<count_true<Args...>::value> { template <typename... Bs> Bar(Bs&&... args) // 编译期校验所有参数都是bool类型 : std::enable_if_t<(std::is_same_v<std::decay_t<Bs>, bool> && ...), bool>(true) { static_assert(sizeof...(Args) == sizeof...(Bs), "传入参数数量与模板参数不匹配"); static_assert(sizeof...(Args) <= 1337, "模板参数数量超出上限"); // 处理参数示例:将参数存入数组遍历 bool params[] = {std::forward<Bs>(args)...}; for (bool b : params) { // 添加你的业务逻辑 } } };
3. 使用示例
// 模板参数为true, false, true,统计true数量为2,继承Foo<2> Bar<true, false, true> bar1({true, false, true}); // 写法二的调用方式 Bar<true, false, true> bar2(true, false, true);
内容的提问来源于stack exchange,提问作者oarfish
相关产品推荐
相关产品推荐

