c++ - C++ 概念的通配符表示“接受此模板参数的任何内容”
问题描述
有没有办法允许一个concept
带有模板参数的,可以接受提供的任何模板参数?
即模板参数占位符的某种通配符魔术?
一个使用示例:
template<class Me, class TestAgainst>
concept derived_from_or_same_as =
std::same_as<Me, TestAgainst> ||
std::derived_from<Me, TestAgainst>;
上面是必需的,因为不幸的是,原始类型的 行为与和的类类型不同。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) { /* */ }
不幸的是,在 C++20 中不允许 auto 作为模板参数占位符。
所以Pair<auto, auto>
暂时不是解决办法。
其他语言在某种程度上允许这样的语法,尽管与此处要求的语义和含义不同,但用法看起来非常相似。
Python:
// Any as wildcard
foo(lst: List[Any]) -> List[str]
爪哇:
// '?' as wildcard
List<String> foo(List<?> lst)
C++20 之前的语法看起来像1:
用例 [a] -尝试接受任何有效的As或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 之前):模板接受 C++ 中的“任何东西”
解决方案
您可以通过修改Pair以接受和检查标记类型Any来实现通配符行为。 concept
让我们首先将Any声明为标签类,无需实现它。
class Any;
现在我们可以创建一个type_matches concept
来检查类型T是否与给定类型A匹配,规则如下:
T匹配A
- 如果A是Any -- 或 --
- 如果T == A或T派生自A
如问题中所述,可以对类类型进行T == A或T派生自A的检查,但原始类型需要添加对.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) { /* */ }
推荐阅读
- angularjs - 我们如何将数据推送到 laravel5 中的数组?
- ios - iOS版Flutter ImageCrop库相机权限错误
- dart - 在 Android 中使用 Flutter Firebase Auth Passwordless SignIn (SignInWithEmailAndLink) 找不到动态链接
- python - 使用 python 进行网页抓取
- c# - 如何将json拆分为空格分隔的字符串?
- angular - 如何在 Angular 7 项目中禁用自动填充
- javascript - 我不知道如何在中间停止该功能
- winforms - C# Windows 窗体 - 想要动态更新文本框值
- php - 为什么我的活动在 octobercms 中不起作用?
- c# - 如何解决 Azure Active Directory 多个用户在同一浏览器中登录而不注销的问题?