如何将 C++20 约束的多个 return 类型要求合并为一个 return 类型要求?
How can I combine several return type requirements of C++20 constraints into one return type requirement?
目前,我已经实现了Allocator concept (which refers to the Boost proposal) using C++20 constraints and concepts:
#include <concepts>
#include <iterator>
template <class A>
concept allocator =
std::copy_constructible<A> &&
std::equality_comparable<A> &&
requires(A a) {
{ a.allocate(0) } -> std::regular;
{ a.allocate(0) } -> std::constructible_from<std::nullptr_t>;
{ a.allocate(0) } -> std::equality_comparable_with<std::nullptr_t>;
{ a.allocate(0) } -> std::random_access_iterator;
{ *a.allocate(0) } -> std::same_as<typename A::value_type&>;
};
您可以看到同一个 allocate
函数有多个 return-type-requirement。有什么方法可以将它们组合成一个 return-type-requirement ,如下所示?
{ a.allocate(0) } -> std::regular &&
std::constructible_from<std::nullptr_t> &&
std::equality_comparable_with<std::nullptr_t> &&
std::random_access_iterator;
不,你不能像这样组合类型约束,但你可以创建一个命名概念
template <class A>
concept allocate_result =
std::regular<A> &&
std::constructible_from<A, std::nullptr_t> &&
std::equality_comparable_with<A, std::nullptr_t> &&
std::random_access_iterator<A>;
并使用它
{ a.allocate(0) } -> allocate_result;
{ *a.allocate(0) } -> std::same_as<typename A::value_type&>;
您还可以通过容器类型参数化 allocator_result
并合并最后一个条件:
template <class A, class Cont>
concept allocator_result =
std::regular<A> &&
std::constructible_from<A, std::nullptr_t> &&
std::equality_comparable_with<A, std::nullptr_t> &&
std::random_access_iterator<A> &&
std::same_as<typename std::remove_pointer<A>::type, typename Cont::value_type&>;
template <class A>
concept allocator =
std::copy_constructible<A> &&
std::equality_comparable<A> &&
requires(A a) {
{ *a.allocate(0) } -> allocator_result<A>;
};
对于这种特殊情况,您应该更严格地遵循这个概念。 allocator_traits<A>::allocate
的return类型要求为allocator_traits<A>::pointer
。所以这就是你应该测试的。就是allocator_traits<A>::pointer
必须满足contiguous iterator和nullable pointer的各种约束。
所以代码应该是这样的:
template<typename P>
concept nullable_pointer =
std::regular<P> &&
std::convertible_to<std::nullptr_t, P> &&
std::assignable_from<P&, std::nullptr_t> &&
std::equality_comparable_with<P, std::nullptr_t>
template<typename P>
concept allocator_pointer =
nullable_pointer<P> &&
std::contiguous_iterator<P>;
template<typename A>
concept allocator =
std::copy_constructible<A> &&
std::equality_comparable<A> &&
requires(A a)
{
{ a.allocate(0) } -> allocator_pointer;
};
目前,我已经实现了Allocator concept (which refers to the Boost proposal) using C++20 constraints and concepts:
#include <concepts>
#include <iterator>
template <class A>
concept allocator =
std::copy_constructible<A> &&
std::equality_comparable<A> &&
requires(A a) {
{ a.allocate(0) } -> std::regular;
{ a.allocate(0) } -> std::constructible_from<std::nullptr_t>;
{ a.allocate(0) } -> std::equality_comparable_with<std::nullptr_t>;
{ a.allocate(0) } -> std::random_access_iterator;
{ *a.allocate(0) } -> std::same_as<typename A::value_type&>;
};
您可以看到同一个 allocate
函数有多个 return-type-requirement。有什么方法可以将它们组合成一个 return-type-requirement ,如下所示?
{ a.allocate(0) } -> std::regular &&
std::constructible_from<std::nullptr_t> &&
std::equality_comparable_with<std::nullptr_t> &&
std::random_access_iterator;
不,你不能像这样组合类型约束,但你可以创建一个命名概念
template <class A>
concept allocate_result =
std::regular<A> &&
std::constructible_from<A, std::nullptr_t> &&
std::equality_comparable_with<A, std::nullptr_t> &&
std::random_access_iterator<A>;
并使用它
{ a.allocate(0) } -> allocate_result;
{ *a.allocate(0) } -> std::same_as<typename A::value_type&>;
您还可以通过容器类型参数化 allocator_result
并合并最后一个条件:
template <class A, class Cont>
concept allocator_result =
std::regular<A> &&
std::constructible_from<A, std::nullptr_t> &&
std::equality_comparable_with<A, std::nullptr_t> &&
std::random_access_iterator<A> &&
std::same_as<typename std::remove_pointer<A>::type, typename Cont::value_type&>;
template <class A>
concept allocator =
std::copy_constructible<A> &&
std::equality_comparable<A> &&
requires(A a) {
{ *a.allocate(0) } -> allocator_result<A>;
};
对于这种特殊情况,您应该更严格地遵循这个概念。 allocator_traits<A>::allocate
的return类型要求为allocator_traits<A>::pointer
。所以这就是你应该测试的。就是allocator_traits<A>::pointer
必须满足contiguous iterator和nullable pointer的各种约束。
所以代码应该是这样的:
template<typename P>
concept nullable_pointer =
std::regular<P> &&
std::convertible_to<std::nullptr_t, P> &&
std::assignable_from<P&, std::nullptr_t> &&
std::equality_comparable_with<P, std::nullptr_t>
template<typename P>
concept allocator_pointer =
nullable_pointer<P> &&
std::contiguous_iterator<P>;
template<typename A>
concept allocator =
std::copy_constructible<A> &&
std::equality_comparable<A> &&
requires(A a)
{
{ a.allocate(0) } -> allocator_pointer;
};