使用概念检查类型 T 是否具有字段 F
Using concepts for checking if a type T has a field F
下面的concept
检查类型T是否有public字段foo:
template<typename T>
concept has_field_foo = requires {
T::foo;
};
有没有一种方法可以实现通用 concept
来检查类型 T 是否具有 public 字段 F,类似(伪代码...字段F不能这样传递):
template<typename T, typename F>
concept has_field = requires {
T::F;
};
检查提供的参数是否具有字段 F 可以通过对函数本身的 requires
约束轻松实现:
// accepts only parameters that have a 'foo' member
void doSomething(auto i) requires requires { i.foo; } { /* */ }
For why (and when) C++20 requires requires
requires
see:
以上方法可以与泛型 case 重载完美共存:
// the unconstrained version
void doSomething(auto i) { /* */ }
将根据提供的参数选择正确的方法。
代码:https://godbolt.org/z/u35Jo3
为了有一个通用的概念,我们可以插入一个宏来帮助我们:
#define CREATE_HAS_FIELD_CONCEPT(field) \
template<typename T> \
concept has_field_##field = requires { \
T::field; \
}
我们其实并没有通用的概念,但是我们可以通过上面的宏轻松生成需要的概念:
CREATE_HAS_FIELD_CONCEPT(foo); // creates the concept: has_field_foo
并使用它(代替上面需要的版本:
void doSomething(has_field_foo auto i) { /* */ }
代码: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!
}
虽然这个可以正常工作:
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!
}
下面的concept
检查类型T是否有public字段foo:
template<typename T>
concept has_field_foo = requires {
T::foo;
};
有没有一种方法可以实现通用 concept
来检查类型 T 是否具有 public 字段 F,类似(伪代码...字段F不能这样传递):
template<typename T, typename F>
concept has_field = requires {
T::F;
};
检查提供的参数是否具有字段 F 可以通过对函数本身的 requires
约束轻松实现:
// accepts only parameters that have a 'foo' member
void doSomething(auto i) requires requires { i.foo; } { /* */ }
For why (and when) C++20 requires
requires
requires
see:
以上方法可以与泛型 case 重载完美共存:
// the unconstrained version
void doSomething(auto i) { /* */ }
将根据提供的参数选择正确的方法。
代码:https://godbolt.org/z/u35Jo3
为了有一个通用的概念,我们可以插入一个宏来帮助我们:
#define CREATE_HAS_FIELD_CONCEPT(field) \
template<typename T> \
concept has_field_##field = requires { \
T::field; \
}
我们其实并没有通用的概念,但是我们可以通过上面的宏轻松生成需要的概念:
CREATE_HAS_FIELD_CONCEPT(foo); // creates the concept: has_field_foo
并使用它(代替上面需要的版本:
void doSomething(has_field_foo auto i) { /* */ }
代码: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!
}
虽然这个可以正常工作:
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!
}