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

Why is there no variable template template parameter?

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

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;它说正在寻求更多激励示例(这很可能已被大流行推迟),所以也许你应该贡献你的!

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

扩展@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