【问题标题】:How can I combine several return type requirements of C++20 constraints into one return type requirement?如何将 C++20 约束的多个返回类型要求合并为一个返回类型要求?
【发布时间】:2020-11-18 16:06:12
【问题描述】:

目前,我已经使用 C++20 constraints and concepts 实现了 Allocator 概念(指的是Boost proposal):

#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;

【问题讨论】:

    标签: c++ c++20 c++-concepts


    【解决方案1】:

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

    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>;
      };
    

    【讨论】:

      【解决方案2】:

      对于这种特殊情况,您应该更严格地遵循这个概念。 allocator_traits&lt;A&gt;::allocate 的返回类型必须为 allocator_traits&lt;A&gt;::pointer。所以这就是你应该测试的。 allocator_traits&lt;A&gt;::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;
        };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-07-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-22
        • 1970-01-01
        • 2017-03-25
        相关资源
        最近更新 更多