While I'm trying to understand the ostream_joiner's std::ranges algorithm requirement concept failure fiasco, I found that GCC implementation of WeaklyIncrementable iterator looks somewhat different from the standard.
GCC 10.2 stdlibc++ "iterator_concept.h" defines weakly_incrementable also requires
- moveable
- __is_signed_integer_like<iter_difference_t<_Iter>>
which seems to requires Iter::different_type is signed integral or can be "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; }
&& requires(const _Tp& __a, const _Tp& __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>
&& movable<_Iter>
&& requires(_Iter __i)
{
typename iter_difference_t<_Iter>;
requires __detail::__is_signed_integer_like<iter_difference_t<_Iter>>;
{ ++__i } -> same_as<_Iter&>;
__i++;
};
This seems more strict than semiregular in the standard that requires only std::copyable.
Why? What benefits do they give?
Is it okey/possible/should to write ostream_joiner that satisfies WeaklyIncrementable iterator?