Signature of take is
template< ranges::viewable_range R, class DifferenceType >
requires /* ... */
constexpr ranges::view auto take( R&& r, DifferenceType&& count );
It is a minor thing but I wonder why DifferenceType
is not some ssize type(practically int64_t
on modern machines).
Is this just to avoid warnings on comparisons of integers of different signednes, or is there some other design reason I am missing. My intuition that having a fixed type would make error messages easier to read, so I wonder what was the motivation.
If somebody is interested in code example, here it is, it feels a bit artificial since I wanted to keep it short, but it is quite possible to pass wrong type to take argument and then error message is unreadable(my favorite part is:
/opt/compiler-explorer/gcc-trunk-20220401/include/c /12.0.1/bits/atomic_base.h:98:3: note: candidate: 'constexpr std::memory_order std::operator|(memory_order, __memory_order_modifier)'
).
#include <vector>
#include <iostream>
#include <ranges>
#include <string>
#include <fmt/format.h>
#include <fmt/ranges.h>
auto get_n(){
return std::string("2");
}
int main() {
std::vector v {2,3,5,7,11};
const auto n = get_n(); //oops this is std::string
auto dont_even = v | std::views::filter([](const int& i){return i%2==1;}) | std::views::take(n);
std::cout << fmt::format("{}", dont_even);
}
CodePudding user response:
It is a minor thing but I wonder why
DifferenceType
is not some ssize type(practicallyint64_t
on modern machines). Is this just to avoid warnings on comparisons of integers of different signednes, or is there some other design reason I am missing.
Iterators for different range adaptors have different difference_type
s. The calculation of difference_type
is sometimes not as simple as you think.
Taking iota_view
as an example, the standard deliberately uses IOTA-DIFF-T(W)
to calculate its difference_type
, which makes the difference_type
of iota_view<uint64_t>
is __int128
and the difference_type
of iota_view<__int128>
is even a customized __detail::__max_diff_type
in listdc .
This is why the second parameter of views::take
is a template and not a specific integer type, but note that the standard also has constraints on DifferenceType
in [range.take.overview]:
The name
views::take
denotes a range adaptor object ([range.adaptor.object]). LetE
andF
be expressions, letT
beremove_cvref_t<decltype((E))>
, and letD
berange_difference_t<decltype((E))>
. Ifdecltype((F))
does not modelconvertible_to<D>
,views::take(E, F)
is ill-formed.
which requires that the DifferenceType
must be convertible to R
's difference_type
, which also allows you to
auto r = std::views::iota(0)
| std::views::take(std::integral_constant<int, 42>{});