C++ 概念的通配符表示“接受此模板参数的任何内容”

Ami*_*rsh 2 c++ templates auto c++-concepts c++20

有没有办法允许concept使用模板参数,可以使用提供的任何模板参数?

\n

即模板参数占位符的某种通配符魔法?

\n

一个使用示例:

\n
template<class Me, class TestAgainst>\nconcept derived_from_or_same_as = \n    std::same_as<Me, TestAgainst> ||\n    std::derived_from<Me, TestAgainst>;\n
Run Code Online (Sandbox Code Playgroud)\n

需要上面的内容是因为不幸的是,原始类型的 行为与和 的类类型不同。is_base_ofderived_from

\n

现在我们可以定义一个Pair concept来检查提供的类型:

\n
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};\n
Run Code Online (Sandbox Code Playgroud)\n

用例 [a] - 接受任何有效的As或As子类型对:

\n
// this works well\nvoid doWithPairOfA(const Pair<A, A> auto& p) { /* */ }\n
Run 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) { /* */ }\n
Run Code Online (Sandbox Code Playgroud)\n

不幸的是,在 C++20 中不允许 auto 作为模板参数占位符

\n

所以Pair<auto, auto>目前还不是解决办法。

\n
\n

其他语言以某种方式允许这种语法,尽管与此处所要求的语义和含义不完全相同,但用法看起来非常相似。

\n

Python:

\n
// Any as wildcard\nfoo(lst: List[Any]) -> List[str]\n
Run Code Online (Sandbox Code Playgroud)\n

爪哇:

\n
// \'?\' as wildcard\nList<String> foo(List<?> lst)\n
Run Code Online (Sandbox Code Playgroud)\n
\n

C++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) { /* */ }\n
Run 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) { /* */ }\n
Run Code Online (Sandbox Code Playgroud)\n

C++20 之前的代码

\n

概念能否提供更好的解决方案?

\n
\n

1关于模板的相关问题(C++20 之前):Templates Accepting \xe2\x80\x9canything\xe2\x80\x9d in C++

\n

Ami*_*rsh 5

您可以通过修改Pair以接受并检查标签类型Any来实现通配符行为 concept

我们首先将Any声明为标签类,无需实现它。

class Any;
Run Code Online (Sandbox Code Playgroud)

现在我们可以创建一个type_matches concept来检查类型T是否与给定类型A匹配,规则如下:

T匹配A

  • 如果A任意 -- 或 --
  • 如果T == A或者如果T从A派生

正如问题中所指出的,可以对类类型进行T == AT派生自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