我可以在类定义中的非类型模板参数包上使用“enable_if”吗?

Can I use `enable_if` on a non-type template parameter pack inside the class definition?

提问人:oarfish 提问时间:10/2/2023 最后编辑:Evgoarfish 更新时间:10/2/2023 访问量:76

问:

我想在可能固定数量的布尔值上模板化一个类,对它们进行计数,并将该数字用作基类的模板参数。像这样的东西

template <int Dimensionality> struct Foo {}; // I want to inherit from this

// helpers to compile-time count the true values among bools
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;
};

// I want something like this, pseudocode
template <bool... Args>
struct Bar : public Foo<count_true<Args...>::value> {
  Bar(bool... args) {
    // do something with the parameters
    static_assert(sizeof...(args) <= 1337);
  }
};

但我找不到办法做到这一点。 似乎有很多与函数的参数包相关的问题,例如enable_if

或者使用模板类型不用于继承,例如

但这些在这种特殊情况下都无济于事。 “伪代码”不编译,因为不是未扩展的参数包。bool... args

我在想这样的东西可能会起作用,但它没有,因为参数包必须是最后一个模板参数:

template <class... Ts>
struct Bar : public Foo<count_true<Ts..., std::enable_if_t<(std::is_same<Ts, bool>::value && ...), bool>>::value> {
…
}

有没有办法做到这一点?这个问题可能有点困惑,因为我真的不知道我在做什么 w.r.t. 模板元编程。

C++ C++20 变量模板

评论

1赞 Evg 10/2/2023
它们之间有什么关系?args...Args...
0赞 oarfish 10/2/2023
我想表达的是,构造函数应该将给定类型的值作为模板参数。因此,如果我实例化,构造函数签名应该变为 。Bar<true, false, false>Bar(bool, bool, bool)
1赞 Evg 10/2/2023
构造函数本身可以是一个模板。怎么办?此外,可以替换为 。template<std::same_as<bool>... Ts> requires(sizeof...(Args) == sizeof...(Ts)) Bar(Ts... args)count_true<Args...>::value(Args + ... + 0)
0赞 oarfish 10/2/2023
这也有效,将是一个替代答案。

答:

6赞 康桓瑋 10/2/2023 #1

但这些在这种特殊情况下都无济于事。“伪代码” 不编译,因为......args 不是未展开的参数 包。bool

您可以使用 展开模板参数。此外,可以简单地用折叠表达代替。decltype()count_true

template <bool... Args>
struct Bar : public Foo<(Args + ... + 0)> {
  Bar(decltype(Args)... args) {
    // do something with the parameters
    static_assert(sizeof...(args) <= 1337);
  }
};

评论

0赞 Barry 10/2/2023
我的错,出于某种原因,我认为这是无效的。
0赞 Red.Wave 10/2/2023
将断言放在类定义中 - 而不是方法 - 可以更好地维护。因为它不依赖于特定于构造函数的任何内容