C ++概念的通配符说“接受此模板参数的任何内容" [英] Wildcard for C++ concepts saying "accepting anything for this template argument"

查看:106
本文介绍了C ++概念的通配符说“接受此模板参数的任何内容"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法允许带有模板参数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) { /* */ }

C ++ 20之前的代码

概念可以提出更好的解决方案吗?

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆