Ami*_*rsh 3 c++ reflection c++-concepts c++20
以下concept检查类型T是否具有公共字段foo:
template<typename T>
concept has_field_foo = requires {
T::foo;
};
Run Code Online (Sandbox Code Playgroud)
有没有办法实现一个泛型concept来检查类型T是否有一个公共字段F,类似于(伪代码......字段F不能像这样传递):
template<typename T, typename F>
concept has_field = requires {
T::F;
};
Run Code Online (Sandbox Code Playgroud)
检查提供的参数是否具有字段F可以通过requires对函数本身的约束轻松实现:
// accepts only parameters that have a 'foo' member
void doSomething(auto i) requires requires { i.foo; } { /* */ }
Run Code Online (Sandbox Code Playgroud)
对于为什么(以及何时)C++20 需要,
requiresrequires请参阅: 为什么我们需要需要需要?
上述方法可以完美地与通用案例重载一起使用:
// the unconstrained version
void doSomething(auto i) { /* */ }
Run Code Online (Sandbox Code Playgroud)
将根据提供的参数选择正确的方法。
代码:https : //godbolt.org/z/u35Jo3
为了有一个通用的概念,我们可以插入一个宏来帮助我们:
#define CREATE_HAS_FIELD_CONCEPT(field) \
template<typename T> \
concept has_field_##field = requires { \
T::field; \
}
Run Code Online (Sandbox Code Playgroud)
我们实际上没有一个通用的概念,但是我们可以使用上面的宏轻松生成所需的概念:
CREATE_HAS_FIELD_CONCEPT(foo); // creates the concept: has_field_foo
Run Code Online (Sandbox Code Playgroud)
并使用它(而不是具有上述要求的版本):
void doSomething(has_field_foo auto i) { /* */ }
Run Code Online (Sandbox Code Playgroud)
代码:https : //godbolt.org/z/R9nQ7Q
实际创建一个概念有一定的价值,因为它可以参与偏序。
使用普通约束我们不会得到偏序,因为原子约束不被认为是等效的,但原子概念是。
因此,基于普通约束的以下代码因歧义而失败:
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!
}
Run Code Online (Sandbox Code Playgroud)
虽然这个可以按需要工作:
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!
}
Run Code Online (Sandbox Code Playgroud)