Проверка наличия в указанном параметре поля F может быть легко достигнута с ограничением requires
на саму функцию:
// accepts only parameters that have a 'foo' member
void doSomething(auto i) requires requires { i.foo; } { /* */ }
Почему (и когда) C ++ 20 требует requires
requires
см .: Почему мы требуем требует требует?
Выше метод может прекрасно жить вместе с generi c регистр перегрузки:
// the unconstrained version
void doSomething(auto i) { /* */ }
правильный метод будет выбран в соответствии с предоставленным параметром.
код: https://godbolt.org/z/u35Jo3
Чтобы иметь общую концепцию c, мы можем добавить макрос, чтобы помочь нам:
#define CREATE_HAS_FIELD_CONCEPT(field) \
template<typename T> \
concept has_field_##field = requires { \
T::field; \
}
У нас на самом деле нет общей концепции c, но мы можем легко сгенерировать требуемая концепция с указанным выше макросом:
CREATE_HAS_FIELD_CONCEPT(foo); // creates the concept: has_field_foo
И использовать его ( вместо версии с требует выше):
void doSomething(has_field_foo auto i) { /* */ }
Код: https://godbolt.org/z/R9nQ7Q
Существует определенная ценность в создании концепции, поскольку она может участвовать в частичном упорядочении.
С помощью В обычном ограничении мы не получаем частичного упорядочения, поскольку ограничения atomi c не считаются эквивалентными, но понятия atom c.
Таким образом, следующий код, основанный на простом ограничении, завершается неудачно с неопределенностью:
void print(auto i) requires requires { i.foo; } {
std::cout << "foo" << std::endl;
}
void print(auto i) requires requires { i.moo; } {
std::cout << "moo" << std::endl;
}
void print(auto i) requires requires { i.moo && i.foo; } {
std::cout << "foo and moo" << std::endl;
}
struct HasFoo { int foo; };
struct HasMoo { int moo; };
struct HasFooAndMoo: HasFoo, HasMoo {};
int main() {
print(HasFoo{});
print(HasMoo{});
print(HasFooAndMoo{}); // compilation error: ambiguity
// all 3 'print' functions are proper candidates
// no partial ordering for constraints, just for concepts!
}
, пока этот работает как нужно:
CREATE_HAS_FIELD_CONCEPT(foo); // creates the concept: has_field_foo
CREATE_HAS_FIELD_CONCEPT(moo); // creates the concept: has_field_moo
void print(has_field_foo auto i) {
std::cout << "foo" << std::endl;
}
void print(has_field_moo auto i) {
std::cout << "moo" << std::endl;
}
template<class P>
concept has_fields_foo_and_moo
= has_field_foo<P> && has_field_moo<P>;
void print(has_fields_foo_and_moo auto i) {
std::cout << "foo and moo" << std::endl;
}
int main() {
print(HasFoo{});
print(HasMoo{});
print(HasFooAndMoo{}); // partial ordering for concepts rocks!
}