问题
Currently, I have implemented the 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&>;
};
You can see there are several return-type-requirements for the same allocate
function. Is there some way to combine them into one single return-type-requirement like the following?
{ a.allocate(0) } -> std::regular &&
std::constructible_from<std::nullptr_t> &&
std::equality_comparable_with<std::nullptr_t> &&
std::random_access_iterator;
回答1:
For this particular case, you should follow the concept more closely. The return type of allocator_traits<A>::allocate
is required to be allocator_traits<A>::pointer
. So that's what you should test. It is allocator_traits<A>::pointer
that must satisfy the various constraints of contiguous iterator and nullable pointer.
So the code should look like this:
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;
};
回答2:
No, you cannot combine type constraints like this, but you can create a named concept
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>;
and use it
{ a.allocate(0) } -> allocate_result;
{ *a.allocate(0) } -> std::same_as<typename A::value_type&>;
You can also parameterize allocator_result
by the container type and incorporate the last condition:
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>;
};
来源:https://stackoverflow.com/questions/63147287/how-can-i-combine-several-return-type-requirements-of-c20-constraints-into-one