Ami*_*rsh 2 c++ templates auto c++-concepts c++20
有没有办法允许concept使用模板参数,可以使用提供的任何模板参数?
即模板参数占位符的某种通配符魔法?
\n一个使用示例:
\ntemplate<class Me, class TestAgainst>\nconcept derived_from_or_same_as = \n std::same_as<Me, TestAgainst> ||\n std::derived_from<Me, TestAgainst>;\nRun Code Online (Sandbox Code Playgroud)\n需要上面的内容是因为不幸的是,原始类型的 行为与和 的类类型不同。is_base_ofderived_from
现在我们可以定义一个Pair concept来检查提供的类型:
template<class P, class First, class Second>\nconcept Pair = requires(P p) {\n requires derived_from_or_same_as<decltype(p.first), First>;\n requires derived_from_or_same_as<decltype(p.second), Second>;\n};\nRun Code Online (Sandbox Code Playgroud)\n用例 [a] - 接受任何有效的As或As子类型对:
\n// this works well\nvoid doWithPairOfA(const Pair<A, A> auto& p) { /* */ }\nRun Code Online (Sandbox Code Playgroud)\n用例 [b] - 接受任何有效对,对内部类型没有限制:
\n// this is *pseudo code* as Pair<auto, auto> is not allowed\nvoid doWithAnyPair(const Pair<auto, auto> auto& p) { /* */ }\nRun Code Online (Sandbox Code Playgroud)\n不幸的是,在 C++20 中不允许 auto 作为模板参数占位符。
\n所以Pair<auto, auto>目前还不是解决办法。
其他语言以某种方式允许这种语法,尽管与此处所要求的语义和含义不完全相同,但用法看起来非常相似。
\nPython:
\n// Any as wildcard\nfoo(lst: List[Any]) -> List[str]\nRun Code Online (Sandbox Code Playgroud)\n爪哇:
\n// \'?\' as wildcard\nList<String> foo(List<?> lst)\nRun Code Online (Sandbox Code Playgroud)\nC++20 之前的语法类似于1:
\n用例 [a] -尝试接受任何有效的As或As子类型对:
\n// not as good as with concepts above, this allows only "pair" of A and A\n// **but rejects sub-types of A, which is not good**\n// and there is no check that this is actually a pair (can be added with SFINAE)\ntemplate<template<class, class> typename PAIR>\nvoid doWithPairOfA(const PAIR<A, A>& p) { /* */ }\nRun Code Online (Sandbox Code Playgroud)\n用例 [b] - 接受任何有效对,对内部类型没有限制:
\n// not as good as we would wish - we do allow any kind of "pair"\n// but there is no check that this is actually a pair (can be added with SFINAE)\ntemplate<template<class, class> typename PAIR, typename ANY1, typename ANY2>\nvoid doWithAnyPair(const PAIR<ANY1, ANY2>& p) { /* */ }\nRun Code Online (Sandbox Code Playgroud)\n\n概念能否提供更好的解决方案?
\n1关于模板的相关问题(C++20 之前):Templates Accepting \xe2\x80\x9canything\xe2\x80\x9d in C++
\n您可以通过修改Pair以接受并检查标签类型Any来实现通配符行为。 concept
我们首先将Any声明为标签类,无需实现它。
class Any;
Run Code Online (Sandbox Code Playgroud)
现在我们可以创建一个type_matches concept来检查类型T是否与给定类型A匹配,规则如下:
T匹配A
正如问题中所指出的,可以对类类型进行T == A或T派生自A的检查,但原始类型需要添加 的测试。std::derived_fromstd::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>;
Run Code Online (Sandbox Code Playgroud)
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>;
};
Run Code Online (Sandbox Code Playgroud)
该代码现在可以允许两个必需的用例。
用例 [a] - 接受任何有效的As或As子类型对:
// can be called with a Pair of As or sub-type of As
void doWithPairOfA(const Pair<A, A> auto& p) { /* */ }
Run Code Online (Sandbox Code Playgroud)
用例 [b] - 接受任何有效对,对内部类型没有限制:
void doWithAnyPair(const Pair<Any, Any> auto& p) { /* */ }
Run Code Online (Sandbox Code Playgroud)
代码: https: //godbolt.org/z/higX9f