Подпись взятия
template< ranges::viewable_range R, class DifferenceType >
requires /* ... */
constexpr ranges::view auto take( R&& r, DifferenceType&& count );
Это мелочь, но мне интересно, почему DifferenceType
не какой-то тип ssize (практически int64_t
на современных машинах).
Это просто для того, чтобы избежать предупреждений о сравнении целых чисел с разными знаками, или есть какая-то другая причина дизайна, которую я упускаю. Моя интуиция заключалась в том, что наличие фиксированного типа облегчило бы чтение сообщений об ошибках, поэтому мне интересно, какова была мотивация.
Если кого-то интересует пример кода, вот он, он кажется немного искусственным, так как я хотел, чтобы он был коротким, но вполне возможно передать неправильный тип, чтобы принять аргумент, и тогда сообщение об ошибке будет нечитаемый (моя любимая часть:
/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);
}
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.
Итераторы для разных адаптеров диапазона имеют разные difference_type
s. Расчет difference_type
иногда не так прост, как вы думаете.
Взяв iota_view
в качестве примера, стандарт намеренно использует IOTA-DIFF-T(W)
для вычисления своего difference_type
, что делает difference_type
из iota_view<uint64_t>
равным __int128
, а difference_type
из iota_view<__int128>
даже настраиваемым __detail::__max_diff_type
в listdc++.
Вот почему второй параметр views::take
является шаблоном, а не конкретным целочисленным типом, но обратите внимание, что стандарт также имеет ограничения на DifferenceType
в [диапазон.взять.обзор]:
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.
который требует, чтобы DifferenceType
был конвертируемым в R
's difference_type
, что также позволяет вам
auto r = std::views::iota(0)
| std::views::take(std::integral_constant<int, 42>{});
Типы целочисленных классов не обязательно являются встроенными целочисленными типами, они также могут быть типами классов, определяемыми реализацией, как это представлено в P1522. Однако введение этих типов целочисленного класса также вызвало некоторые проблемы, которые были решены с помощью P2393 в C++23.
ах, я не подумал о iota, отличный пример/причина, знаете ли вы, почему он не ограничен (с использованием требований) целочисленными типами (может быть, потому, что некоторые из типов diff нестандартны?)