为什么没有可变模板模板参数?
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
- 为什么目前没有变量模板模板parameters/arguments?
- 提案的状态如何?
- 是否有任何可能的变量模板模板替代方案parameters/arguments?
您已经链接到提案,所以您基本上已经自己回答了问题。您可能不知道可以回答“状态”问题的 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>
而不是别名来调用它。
示例 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
.
我打算创建一个带有(可变)模板模板参数和一个类型名称的变量模板:
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
- 为什么目前没有变量模板模板parameters/arguments?
- 提案的状态如何?
- 是否有任何可能的变量模板模板替代方案parameters/arguments?
您已经链接到提案,所以您基本上已经自己回答了问题。您可能不知道可以回答“状态”问题的 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>
而不是别名来调用它。
示例 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
.