Есть ли способ разрешить concept
с аргументами шаблона , чтобы быть в порядке с любым предоставленным параметром шаблона?
Т.е. какой-то мага подстановки c для заполнителя аргумента шаблона?
Пример использования:
template<class Me, TestAgainst>
concept derived_from_or_same_as =
std::same_as<Me, TestAgainst> ||
std::derived_from<decltype(p.first), First>;
Выше необходимо, потому что, к сожалению, примитивные типы ведут себя иначе чем типы классов для 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] - принять любую действительную пару Как или подтип Как :
// 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) { /* */ }
К сожалению, auto не допускается в качестве заполнителя аргумента шаблона в C ++ 20 .
Так что Pair<auto, auto>
не является решение на данный момент.
Другие языки допускают такой синтаксис в некотором роде, хотя и не с такой же точной семантикой и значением, как здесь, но использование выглядит очень похоже.
Python:
// Any as wildcard
foo(lst: List[Any]) -> List[str]
Java:
// ? as wildcard
List<String> foo(List<?> lst)
Синтаксис до C ++ 20 выглядел бы как-то например 1 :
Вариант использования [a] - при попытке принять любую действительную пару 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] - принять любую допустимую пару, без r ограничения на внутренние типы:
// 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 код
Могут ли концепции представить лучшее решение?
1 Смежный вопрос (до C ++ 20, для шаблонов, а не для концепций): Шаблоны, принимающие "что-нибудь" в C ++