C++ 概念的通配符表示 "accepting anything for this template argument"
Wildcard for C++ concepts saying "accepting anything for this template argument"
有没有办法让带有 模板参数 的 concept
与提供的任何模板参数兼容?
即模板参数占位符的某种通配符魔术?
用法举例:
template<class Me, class TestAgainst>
concept derived_from_or_same_as =
std::same_as<Me, TestAgainst> ||
std::derived_from<Me, TestAgainst>;
以上是必需的,因为不幸的是 原始类型 behave differently 比 class 类型 for is_base_of
和 derived_from
.
现在我们可以定义一个 Pair concept
来检查提供的类型:
template<class P, class First, class Second>
concept Pair = requires(P p) {
requires derived_from_or_same_as<decltype(p.first), First>;
requires derived_from_or_same_as<decltype(p.second), Second>;
};
用例 [a] - 接受任何有效的 As 对或 As 的子类型:
// this works well
void doWithPairOfA(const Pair<A, A> auto& p) { /* */ }
用例[b] - 接受任何有效对,对内部类型没有限制:
// this is *pseudo code* as Pair<auto, auto> is not allowed
void doWithAnyPair(const Pair<auto, auto> auto& p) { /* */ }
不幸的是,。
所以Pair<auto, auto>
暂时不是解决方案。
其他语言在某种程度上允许这样的语法,虽然与此处要求的语义和含义不同,但用法看起来非常相似。
Python:
// Any as wildcard
foo(lst: List[Any]) -> List[str]
Java:
// '?' as wildcard
List<String> foo(List<?> lst)
C++20 之前的语法类似于1:
用例 [a] - 尝试 接受任何有效的 As 对或 As 的子类型=64=]作为:
// not as good as with concepts above, this allows only "pair" of A and A
// **but rejects sub-types of A, which is not good**
// and there is no check that this is actually a pair (can be added with SFINAE)
template<template<class, class> typename PAIR>
void doWithPairOfA(const PAIR<A, A>& p) { /* */ }
用例[b] - 接受任何有效对,对内部类型没有限制:
// not as good as we would wish - we do allow any kind of "pair"
// but there is no check that this is actually a pair (can be added with SFINAE)
template<template<class, class> typename PAIR, typename ANY1, typename ANY2>
void doWithAnyPair(const PAIR<ANY1, ANY2>& p) { /* */ }
概念能否提供更好的解决方案?
1 关于模板的相关问题(C++20 之前):Templates accepting “anything” in C++
您可以通过修改 Pair concept
来实现 通配符行为 接受并检查标签类型 Any.
我们先把Any声明为标签class,不用实现了
class Any;
现在我们可以创建一个 type_matches concept
来检查类型 T 匹配给定类型 A,规则如下:
T 匹配 A
- 如果A是任何
-- 或 --
- if T==A 或者如果 T 来自 A
如问题中所述,检查 T==A 或 T派生自 A 可以针对 class 类型 仅使用 std::derived_from
但是 原始类型 需要为 std::same_as
添加测试。
通配符匹配可通过以下代码实现:
template<class Me, class TestAgainst>
concept type_matches =
std::same_as<TestAgainst, Any> ||
std::same_as<Me, TestAgainst> ||
std::derived_from<Me, TestAgainst>;
Pair 概念将修改为:
template<class P, class First, class Second>
concept Pair = requires(P p) {
requires type_matches<decltype(p.first), First>;
requires type_matches<decltype(p.second), Second>;
};
代码现在可以允许两个必需的用例。
用例 [a] - 接受任何有效的 As 对或 As 的子类型:
// can be called with a Pair of As or sub-type of As
void doWithPairOfA(const Pair<A, A> auto& p) { /* */ }
用例[b] - 接受任何有效对,对内部类型没有限制:
void doWithAnyPair(const Pair<Any, Any> auto& p) { /* */ }
有没有办法让带有 模板参数 的 concept
与提供的任何模板参数兼容?
即模板参数占位符的某种通配符魔术?
用法举例:
template<class Me, class TestAgainst>
concept derived_from_or_same_as =
std::same_as<Me, TestAgainst> ||
std::derived_from<Me, TestAgainst>;
以上是必需的,因为不幸的是 原始类型 behave differently 比 class 类型 for is_base_of
和 derived_from
.
现在我们可以定义一个 Pair concept
来检查提供的类型:
template<class P, class First, class Second>
concept Pair = requires(P p) {
requires derived_from_or_same_as<decltype(p.first), First>;
requires derived_from_or_same_as<decltype(p.second), Second>;
};
用例 [a] - 接受任何有效的 As 对或 As 的子类型:
// this works well
void doWithPairOfA(const Pair<A, A> auto& p) { /* */ }
用例[b] - 接受任何有效对,对内部类型没有限制:
// this is *pseudo code* as Pair<auto, auto> is not allowed
void doWithAnyPair(const Pair<auto, auto> auto& p) { /* */ }
不幸的是,
所以Pair<auto, auto>
暂时不是解决方案。
其他语言在某种程度上允许这样的语法,虽然与此处要求的语义和含义不同,但用法看起来非常相似。
Python:
// Any as wildcard
foo(lst: List[Any]) -> List[str]
Java:
// '?' as wildcard
List<String> foo(List<?> lst)
C++20 之前的语法类似于1:
用例 [a] - 尝试 接受任何有效的 As 对或 As 的子类型=64=]作为:
// not as good as with concepts above, this allows only "pair" of A and A
// **but rejects sub-types of A, which is not good**
// and there is no check that this is actually a pair (can be added with SFINAE)
template<template<class, class> typename PAIR>
void doWithPairOfA(const PAIR<A, A>& p) { /* */ }
用例[b] - 接受任何有效对,对内部类型没有限制:
// not as good as we would wish - we do allow any kind of "pair"
// but there is no check that this is actually a pair (can be added with SFINAE)
template<template<class, class> typename PAIR, typename ANY1, typename ANY2>
void doWithAnyPair(const PAIR<ANY1, ANY2>& p) { /* */ }
概念能否提供更好的解决方案?
1 关于模板的相关问题(C++20 之前):Templates accepting “anything” in C++
您可以通过修改 Pair concept
来实现 通配符行为 接受并检查标签类型 Any.
我们先把Any声明为标签class,不用实现了
class Any;
现在我们可以创建一个 type_matches concept
来检查类型 T 匹配给定类型 A,规则如下:
T 匹配 A
- 如果A是任何 -- 或 --
- if T==A 或者如果 T 来自 A
如问题中所述,检查 T==A 或 T派生自 A 可以针对 class 类型 仅使用 std::derived_from
但是 原始类型 需要为 std::same_as
添加测试。
通配符匹配可通过以下代码实现:
template<class Me, class TestAgainst>
concept type_matches =
std::same_as<TestAgainst, Any> ||
std::same_as<Me, TestAgainst> ||
std::derived_from<Me, TestAgainst>;
Pair 概念将修改为:
template<class P, class First, class Second>
concept Pair = requires(P p) {
requires type_matches<decltype(p.first), First>;
requires type_matches<decltype(p.second), Second>;
};
代码现在可以允许两个必需的用例。
用例 [a] - 接受任何有效的 As 对或 As 的子类型:
// can be called with a Pair of As or sub-type of As
void doWithPairOfA(const Pair<A, A> auto& p) { /* */ }
用例[b] - 接受任何有效对,对内部类型没有限制:
void doWithAnyPair(const Pair<Any, Any> auto& p) { /* */ }