C ++概念的通配符说“接受此模板参数的任何内容" [英] Wildcard for C++ concepts saying "accepting anything for this template argument"
问题描述
有没有办法允许带有模板参数的concept
与提供的任何模板参数一起使用?
Is there a way to allow a concept
with template arguments, to be ok with any template parameter provided?
即模板参数占位符的某种通配符?
I.e. some kind of wildcard magic for template argument placeholder?
用法示例:
template<class Me, TestAgainst>
concept derived_from_or_same_as =
std::same_as<Me, TestAgainst> ||
std::derived_from<decltype(p.first), First>;
Above is needed because unfortunately primitive types behave differently than class types for is_base_of
and derived_from
.
现在,我们可以定义一个 Pair concept
来检查提供的类型:
Now we can define a Pair concept
that checks the provided types:
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 的子类型:
Use case [a] - accept any valid pair of As or sub-type of 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) { /* */ }
不幸的是,不允许将自动用作模板参数C ++ 20中的占位符.
所以Pair<auto, auto>
暂时不是解决方案.
So Pair<auto, auto>
is not the solution for now.
其他语言以某种方式允许这样的语法,尽管其语义和含义与此处要求的完全不同,但是用法看起来非常相似.
Other languages allow such a syntax in a way, though not with the same exact semantics and meaning as requested here, but the usage looks quite similar.
Python:
// Any as wildcard
foo(lst: List[Any]) -> List[str]
Java:
// ? as wildcard
List<String> foo(List<?> lst)
C ++ 20之前的语法类似于 1 :
用例[a]-尝试接受任何有效的 As 对或 As 的子类型:
Use case [a] - trying to accept any valid pair of As or sub-type of As:
// 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之前,关于模板而不是概念): 接受"anything"的模板在C ++中
1 Related question (pre C++20, on templates not on concepts): Templates accepting "anything" in C++
推荐答案
您可以通过修改对 concept
来实现 通配符行为 接受并检查标签类型任何.
You can achieve wildcard behavior by modifying the Pair concept
to accept and check a tag type Any.
我们首先将 Any 声明为标记类,无需实现它.
Let's first declare Any as a tag class, no need to implement it.
class Any;
现在我们可以创建 type_matches concept
来检查类型 T 是否与给定的类型 A 相匹配>,并遵循以下规则:
Now we can create a type_matches concept
to check if a type T matches a given type A, with the following rules:
T 匹配 A
T matches A
- 如果 A 是 Any -或-
- 如果 T == A 或 T 是从 A 派生的
- if A is Any -- or --
- if T==A or if T is derived from A
问题中指出, T == A 或 T 的检查是从 A 派生的可以仅使用std::derived_from
来针对类类型进行制作,但是原始类型需要添加针对std::same_as
的测试.
As noted in the question, the check for T==A or T is derived from A can be made for class types just with std::derived_from
however primitive types require adding the test for 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>;
对概念将修改为:
The Pair concept would be modified to:
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>;
};
该代码现在可以允许两个必需的用例.
The code can allow now both required use cases.
用例[a]-接受任何有效的 As 对或 As 的子类型:
Use case [a] - accept any valid pair of As or sub-type of 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) { /* */ }
代码: https://godbolt.org/z/higX9f
这篇关于C ++概念的通配符说“接受此模板参数的任何内容"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!