为什么没有可变模板模板参数?

问题描述

我打算创建一个带有(变量)模板模板参数和一个类型名的变量模板:

template <template <typename> auto MetaPredicate,typename T>
constexpr bool has_predicate_v_ = requires {
  { MetaPredicate<T> } -> std::convertible_to<bool>;
}

期望在哪里:

template <typename T>
struct dummy_01 {
    inline static constexpr bool value = true;
};

template <typename T>
inline constexpr bool dummy_01_v = dummy_01<T>::value;

std::cout << std::boolalpha << has_predicate_v_<dummy_01_v,int> << '\n'; // true

但这行不通。如果它们存在于标准中会很有用。

另一种情况是创建元函数count_if

template <typename Type,template <typename> bool Predicate>
struct count_if {
    inline static constexpr size_t value = /** ... **/;
};

template <typename Type,template <typename> bool Predicate>
inline constexpr size_t count_if_v = count_if<Type,Predicate>::value;

// ...
count_if_v<std::tuple<int,double,void,size_t,unsigned short>,std::is_integral_v> // yields to 3

还有一个与我的问题相关的提案:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2008r0.html

  • 为什么当前没有可变的模板模板参数/参数?
  • 提案的状态如何?
  • 对于可变模板-模板参数/参数是否有任何可能的替代方案?

解决方法

您已经链接到该提案,因此您自己基本上已经回答了这个问题。您可能不知道可以回答“状态”问题的 paper tracker;它说正在寻找更多激励性的例子(这很可能被大流行推迟了),所以也许你应该贡献你的!

至于替代方案,通常的方法是关键在 trait 而不是辅助变量模板。显然,新代码可能必须使用辅助特征类模板包装(基础)变量模板才能利用这一点,但它确实有效。

,

扩展@DavisHerring 的回答:我认为它几乎没有用处:我真的没有看到直接使用辅助变量模板而不是 trait 的优势。这是例如我会为你的两个例子做什么:

C++20 中,我实际上会写一个 concept

template <template <typename> class Predicate,typename T>
concept is_predicate = requires {
  std::same_as<decltype(Predicate<T>::value),bool>;
};

确保给定谓词具有静态 bool 成员变量 value。在此之前,您可能会另外使用 std::enable_if 或根本不使用 SFINAE。

示例 1:

template <template <typename> class MetaPredicate,typename T>
requires is_predicate<MetaPredicate,T>
constexpr bool has_predicate_v_ = requires {
  std::same_as<decltype(MetaPredicate<T>::value),bool>;
};

然后使用特征 has_predicate_v_<dummy_01,int> 而不是别名来调用它。

Try it here

示例 2:

template <template <typename> class Predicate,typename... Ts>
requires (is_predicate<Predicate,Ts> && ...)
struct count_if {
  inline static constexpr size_t count = ((Predicate<Ts>::value == true ? 1 : 0) + ...);
};

并再次使用特征 std::is_integral 调用它:count_if<std::is_integral,int,double>::count

Try it here