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

能否在类定义中对非类型模板参数包使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 18:40:23