关于C++20中的ranges库,我有以下问题:
设std::ranges::contiguous_range<T>为任意类型T。
我可以假设std::ranges::sized_range<T>
发布于 2020-10-19 18:48:29
不,不是每个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>);另一个例子是,给定一些std::string对象s和一些谓词p,或者:
s | std::views::take_while(p)s | std::views::drop_while(p)这里的结果范围仍然是连续的,但是我们不知道它在哪里结束(在第一种情况下)或者从哪里开始(在第二种情况下),所以我们不知道它的大小。
发布于 2020-10-19 21:03:13
由于哨兵的存在,contiguous_range<T>不足以被视为sized_range<T>。但是,如果将contiguous_range<T>与common_range<T>组合(这要求哨兵是迭代器),那么sized_range<T>也必须是真的。
这是逻辑。contiguous_range<T>也是random_access_range<T>。random_access_range<T>在一定程度上意味着是真的。 is_same, sentinel_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)对于类型为T的t有效。
是有效的 if T建模ranges::forward_range<T> (它确实建模),sentinel_t<T>和iterator_t<T>建模std::sized_sentinel_for<sentinel_t<T>, iterator_t<T>>。
如前所述,确实如此。
发布于 2020-10-19 18:49:07
不是的。
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>>>;
};正如您所看到的,它是requires random_access_range,即:
template<class T>
concept random_access_range =
ranges::bidirectional_range<T> && std::random_access_iterator<ranges::iterator_t<T>>;另一方面,requires bidirectional_range,也就是:
template<class T>
concept bidirectional_range =
ranges::forward_range<T> && std::bidirectional_iterator<ranges::iterator_t<T>>;哪个requires forward_range,即:
template<class T>
concept forward_range =
range::input_range<T> && std::forward_iterator<ranges::iterator_t<T>>;以及requires input_range,所以它需要:
template<class T>
concept input_range =
ranges::range<T> && std::input_iterator<ranges::iterator_t<T>>;而range只requires std::ranges::begin()和std::ranges::end()对于给定的T有效。
你可以和那些std::XXX_iterator玩类似的游戏,没有任何std::ranges::size (支持sized_range)的东西。
https://stackoverflow.com/questions/64433293
复制相似问题