为什么 std::ranges::views::take 使用模板化类型来区分?
Why is std::ranges::views::take using templated type for difference?
签名是
template< ranges::viewable_range R, class DifferenceType >
requires /* ... */
constexpr ranges::view auto take( R&& r, DifferenceType&& count );
这是一件小事,但我想知道为什么 DifferenceType
不是某种 ssize 类型(在现代机器上实际上是 int64_t
)。
这只是为了避免在比较不同符号的整数时发出警告,还是我遗漏了其他一些设计原因。我的直觉是固定类型会使错误消息更易于阅读,所以我想知道动机是什么。
如果有人对代码示例感兴趣,就在这里,感觉有点做作,因为我想保持简短,但很有可能传递错误的类型来接受参数,然后错误消息是 unreadable(我最喜欢的部分是:
/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(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.
不同范围适配器的迭代器具有不同的 difference_type
。 difference_type
的计算有时候并没有你想的那么简单
以iota_view
为例,标准故意用IOTA-DIFF-T(W)
来计算其difference_type
,使得iota_view<uint64_t>
的difference_type
为__int128
和 iota_view<__int128>
的 difference_type
甚至是 listdc++ 中的自定义 __detail::__max_diff_type
。
这就是为什么views::take
的第二个参数是模板而不是具体的整数类型的原因,但是注意标准对[range.take.overview]中的DifferenceType
也有约束:
The name views::take
denotes a range adaptor object
([range.adaptor.object]). Let E
and F
be expressions, let T
be
remove_cvref_t<decltype((E))>
, and let D
be
range_difference_t<decltype((E))>
. If decltype((F))
does not model
convertible_to<D>
, views::take(E, F)
is ill-formed.
这要求 DifferenceType
必须可以转换为 R
的 difference_type
,这也允许您
auto r = std::views::iota(0)
| std::views::take(std::integral_constant<int, 42>{});
签名是
template< ranges::viewable_range R, class DifferenceType >
requires /* ... */
constexpr ranges::view auto take( R&& r, DifferenceType&& count );
这是一件小事,但我想知道为什么 DifferenceType
不是某种 ssize 类型(在现代机器上实际上是 int64_t
)。
这只是为了避免在比较不同符号的整数时发出警告,还是我遗漏了其他一些设计原因。我的直觉是固定类型会使错误消息更易于阅读,所以我想知道动机是什么。
如果有人对代码示例感兴趣,就在这里,感觉有点做作,因为我想保持简短,但很有可能传递错误的类型来接受参数,然后错误消息是 unreadable(我最喜欢的部分是:
/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
。 difference_type
的计算有时候并没有你想的那么简单
以iota_view
为例,标准故意用IOTA-DIFF-T(W)
来计算其difference_type
,使得iota_view<uint64_t>
的difference_type
为__int128
和 iota_view<__int128>
的 difference_type
甚至是 listdc++ 中的自定义 __detail::__max_diff_type
。
这就是为什么views::take
的第二个参数是模板而不是具体的整数类型的原因,但是注意标准对[range.take.overview]中的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
的 difference_type
,这也允许您
auto r = std::views::iota(0)
| std::views::take(std::integral_constant<int, 42>{});