Wildcard for C++ concepts saying “accepting anything for this template argument”

痞子三分冷 提交于 2020-03-20 07:39:38

问题


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?

A usage example:

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.

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>;
};

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) { /* */ }

Use case [b] - accept any valid pair, no restrictions on the inner types:

// this is *pseudo code* as Pair<auto, auto> is not allowed
void doWithAnyPair(const Pair<auto, auto> auto& p) { /* */ }

Unfortunately, auto is not allowed as template argument placeholder in C++20.

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)

The pre C++20 syntax would look something like1:

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) { /* */ }

Use case [b] - accept any valid pair, no restrictions on the inner types:

// 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) { /* */ }

Pre C++20 code

Can concepts present a better solution?


1 Related question (pre C++20, on templates not on concepts): Templates accepting "anything" in C++


回答1:


You can achieve wildcard behavior by modifying the Pair concept to accept and check a tag type Any.

Let's first declare Any as a tag class, no need to implement it.

class Any;

Now we can create a type_matches concept to check if a type T matches a given type A, with the following rules:

T matches A

  • if A is Any -- or --
  • if T==A or if T is derived from A

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.

The wildcard match would be achieved with the following code:

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.

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) { /* */ }

Use case [b] - accept any valid pair, no restrictions on the inner types:

void doWithAnyPair(const Pair<Any, Any> auto& p) { /* */ }

Code: https://godbolt.org/z/higX9f



来源:https://stackoverflow.com/questions/60400537/wildcard-for-c-concepts-saying-accepting-anything-for-this-template-argument

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!