Почему в GCC stdlibc определяется слабовыражаемый итератор, требующий перемещения, и его difference_type должен быть целым? Какие преимущества они дают?

#c #gcc #c 20 #c -concepts #range-v3

#c #gcc #c 20 #c -концепции #диапазон-v3

Вопрос:

Пока я пытаюсь понять фиаско концепции требований к алгоритму std ::ranges от ostream_joiner, я обнаружил, что реализация слабовыражаемого итератора GCC выглядит несколько иначе, чем стандартная.

GCC 10.2 stdlibc «iterator_concept.h» определяет слабый_временный итератор, также требует

  • moveable
  • __is_signed_integer_like<iter_difference_t<_Iter>>
    который, по-видимому, требует Iter::different_type является целым со знаком или может быть «long long».
    template<typename _Tp> requires requires { typename _Tp::difference_type; }
     struct incrementable_traits<_Tp>
     { using difference_type = typename _Tp::difference_type; };
  
   template<typename _Tp>
     requires (!requires { typename _Tp::difference_type; }
               amp;amp; requires(const _Tpamp; __a, const _Tpamp; __b)
               {
                 requires (!is_void_v<remove_pointer_t<_Tp>>); // PR c  /78173
                 { __a - __b } -> integral;
               })
     struct incrementable_traits<_Tp>
     {
       using difference_type
         = make_signed_t<decltype(std::declval<_Tp>() - std::declval<_Tp>())>;
     };
   ...
   template<typename _Tp>
     using iter_difference_t = __detail::__iter_diff_t<remove_cvref_t<_Tp>>;
   ...
     using __max_diff_type = long long;
     ...
     template<typename _Tp>
       concept __is_signed_integer_like = signed_integral<_Tp>
         || same_as<_Tp, __max_diff_type>;
   ...
   /// Requirements on types that can be incremented with   .
   template<typename _Iter>
     concept weakly_incrementable = default_initializable<_Iter>
       amp;amp; movable<_Iter>
       amp;amp; requires(_Iter __i)
       {
         typename iter_difference_t<_Iter>;
         requires __detail::__is_signed_integer_like<iter_difference_t<_Iter>>;
         {   __i } -> same_as<_Iteramp;>;
         __i  ;
       };
  

Это кажется более строгим, чем полурегулярным в стандарте, который требует только std::copyable .

Почему? Какие преимущества они дают?

Нормально ли / возможно / следует ли писать ostream_joiner, который удовлетворяет слабовыражаемому итератору?

Комментарии:

1. Потому что так сказано в стандарте . В чем, собственно, заключается «фиаско»?

2.@T.C. О, действительно. Существуют оба exp::ranges::слабовыражаемый en.cppreference.com/w/cpp/experimental/ranges/iterator /… и std::weakly_incrementable en.cppreference.com/w/cpp/iterator/weakly_incrementable уже. В любом случае, почему они заменили на moveable и решили не определять «полурегулярный»? Что касается фиаско, ostream_joiner нельзя использовать в качестве итератора с алгоритмами диапазонов. Однако теперь я вижу, что ostream_iterator теперь удовлетворяет требованию std::default_initializable, в то время как ostream_joiner еще не добавил свой конструктор по умолчанию.

3. @T.C. Можно ли просто добавить конструктор по умолчанию в ostream_joiner для использования с алгоритмами диапазонов?