ple*_*ndo 22 c++ iterator stl language-lawyer c++20
我有以下关于 C++20 中的 range 库的问题:
让std::ranges::contiguous_range<T>一个任意类型T.
我可以假设std::ranges::sized_range<T>吗?
Bar*_*rry 24
不,并非每个contiguous_range都是sized_range.
最简单的例子是以空字符结尾的字符串。它是连续的,但我们不知道它的大小O(1)。我们可以使用哨兵轻松表示这样的事情:
struct ntbs_sentinel {
bool operator==(char const* p) const {
return *p == '\0';
}
};
struct ntbs {
char const* p;
char const* begin() const { return p; }
ntbs_sentinel end() const { return {}; }
};
static_assert(std::ranges::contiguous_range<ntbs>);
static_assert(!std::ranges::sized_range<ntbs>);
Run Code Online (Sandbox Code Playgroud)
另一个例子是,给定一些std::string对象s和一些谓词p,要么:
s | std::views::take_while(p)s | std::views::drop_while(p)这里的结果范围仍然是连续的,但我们不知道它在哪里结束(在第一种情况下)或从哪里开始(在第二种情况下)所以我们不知道它的大小是多少。
Nic*_*las 11
由于哨兵的存在,作为 acontiguous_range<T>不足以被视为 a sized_range<T>。然而,如果你结合contiguous_range<T>with common_range<T>(这要求哨兵是一个迭代器),那么sized_range<T>也必须为真。
这是逻辑。Acontiguous_range<T>也是random_access_range<T>. 并且random_access_range<T>部分random_access_iterator<iterator_t<T>>是真的。 common_range<T>意味着is_same<iterator_t<T>, sentinel_t<T>>. 因此,random_access_iterator<sentinel_t<T>>也必须是真实的。
现在,random_access_iterator<It> 规定要求即std::sized_sentinel_for<I, I>是如此。由于iterator_t<T>和sentinel_t<T>是同一类型,这意味着它std::sized_sentinel_for<sentinel_t<T>, iterator_t<T>>也必须为真。
那么,让我们来看看sized_range<T>。这要求std::ranges::size(t)对 at类型有效T。
ranges::size<T>如果T模型ranges::forward_range<T>(它确实如此)和sentinel_t<T>和iterator_t<T>模型是有效的std::sized_sentinel_for<sentinel_t<T>, iterator_t<T>>。
如前所述,它确实如此。
不。
contiguous_range 是:
template<class T>
concept contiguous_range =
ranges::random_access_range<T> &&
std::contiguous_iterator<ranges::iterator_t<T>> &&
requires(T& t) {
{ ranges::data(t) } ->
std::same_as<std::add_pointer_t<ranges::range_reference_t<T>>>;
};
Run Code Online (Sandbox Code Playgroud)
并且,如您所见,它requires random_access_range是:
template<class T>
concept random_access_range =
ranges::bidirectional_range<T> && std::random_access_iterator<ranges::iterator_t<T>>;
Run Code Online (Sandbox Code Playgroud)
另一方面,requires bidirectional_range,即:
template<class T>
concept bidirectional_range =
ranges::forward_range<T> && std::bidirectional_iterator<ranges::iterator_t<T>>;
Run Code Online (Sandbox Code Playgroud)
其中requires forward_range,即:
template<class T>
concept forward_range =
range::input_range<T> && std::forward_iterator<ranges::iterator_t<T>>;
Run Code Online (Sandbox Code Playgroud)
那requires input_range,所以它需要:
template<class T>
concept input_range =
ranges::range<T> && std::input_iterator<ranges::iterator_t<T>>;
Run Code Online (Sandbox Code Playgroud)
而range只有requires那个std::ranges::begin()并且std::ranges::end()对 given 有效T。
你可以用那些std::XXX_iterators玩类似的游戏。没有任何东西可以用于std::ranges::size(启用sized_range)。