1

I'm planning to create a variable template that takes (variable) template-template parameter and one typename:

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

Where the expectations are:

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

But that doesn't work. It would be useful if they exist in standard.

Another case is to create a metafunction 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

There is also a proposal relating to my question: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2008r0.html

  • Why are there currently no variable template-template parameters/arguments?
  • What is the status of the proposal?
  • Are there any possible alternatives for variable template-template parameters/arguments?
Desmond Gold
  • 1,517
  • 1
  • 7
  • 19

2 Answers2

2

You already linked to the proposal, so you’ve largely answered the question yourself. You might not know about the paper tracker that can answer the “status” question; it says that more motivating examples are sought (which might very well have been delayed by the pandemic), so maybe you should contribute yours!

As for alternatives, the usual one is to key on the trait rather than the helper variable template. Obviously new code might have to wrap a (foundational) variable template with a helper trait class template to take advantage of this, but it works.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76
0

To extend @DavisHerring's answer: I think there is little use of it: I don't really see the advantage of using the helper variable template instead of the trait directly. Here is e.g. what I would do for your two examples:

In C++20 I would actually write a concept

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

that makes sure that a given predicate has a static bool member variable value. Before that you might additionally use std::enable_if instead or not use SFINAE at all.

Example 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>;
};

and then call it with the trait has_predicate_v_<dummy_01, int> instead of the alias.

Try it here

Example 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) + ...);
};

and again call it with the trait std::is_integral instead: count_if<std::is_integral, int, double>::count.

Try it here

2b-t
  • 2,414
  • 1
  • 10
  • 18