如何将 C++20 约束的多个返回类型要求合并为一个返回类型要求?

康桓瑋*_*康桓瑋 13 c++ c++-concepts c++20

目前,我已经使用 C++20约束和概念实现了分配器概念(指的是Boost 提案):

#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&>;
  };
Run Code Online (Sandbox Code Playgroud)

您可以看到同一个函数有多个return-type-requirementallocate。有没有办法将它们组合成一个单一的返回类型要求,如下所示?

{ a.allocate(0) } -> std::regular &&
                     std::constructible_from<std::nullptr_t> &&
                     std::equality_comparable_with<std::nullptr_t> &&
                     std::random_access_iterator;
Run Code Online (Sandbox Code Playgroud)

n. *_* m. 10

不,你不能像这样组合类型约束,但你可以创建一个命名概念

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>;
Run Code Online (Sandbox Code Playgroud)

并使用它

{ a.allocate(0) } -> allocate_result;
{ *a.allocate(0) } -> std::same_as<typename A::value_type&>;
Run Code Online (Sandbox Code Playgroud)

您还可以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>;
  };
Run Code Online (Sandbox Code Playgroud)


Nic*_*las 8

对于这种特殊情况,您应该更密切地遵循这个概念。的返回类型allocator_traits<A>::allocate必须是allocator_traits<A>::pointer。所以这就是你应该测试的。就是allocator_traits<A>::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;
  };
Run Code Online (Sandbox Code Playgroud)