Is a contiguous_range always a sized_range?



我对 C++20 中的范围库有以下问题:

任意类型 Tstd::ranges::contiguous_range<T>

我可以假设std::ranges::sized_range<T>吗?

不,不是每个contiguous_range都是sized_range

最简单的示例是以 null 结尾的字符串。它是连续的,但我们不知道它的大小O(1)时间。我们可以使用哨兵轻松表示这样的事情:

struct ntbs_sentinel {
bool operator==(char const* p) const {
return *p == '';
}
};
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)

这里的结果范围仍然是连续的,但我们不知道它的结束位置(在第一种情况下)或从哪里开始(在第二种情况下),所以我们不知道它的大小是多少。

由于哨兵的存在,作为一个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>部分意味着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)对类型Tt有效。

如果T模型ranges::forward_range<T>(确实如此),并且sentinel_t<T>iterator_t<T>模型std::sized_sentinel_for<sentinel_t<T>, iterator_t<T>>,则ranges::size<T>有效。

如前所述,确实如此。

No.

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>>>;
};

而且,如您所见,它requiresrandom_access_range,即:

template<class T>
concept random_access_range =
ranges::bidirectional_range<T> && std::random_access_iterator<ranges::iterator_t<T>>;

另一方面,requiresbidirectional_range,即:

template<class T>
concept bidirectional_range =
ranges::forward_range<T> && std::bidirectional_iterator<ranges::iterator_t<T>>;

其中requiresforward_range,即:

template<class T>
concept forward_range =
range::input_range<T> && std::forward_iterator<ranges::iterator_t<T>>;

并且requiresinput_range,因此需要:

template<class T>
concept input_range =
ranges::range<T> && std::input_iterator<ranges::iterator_t<T>>;

rangerequiresstd::ranges::begin()std::ranges::end()对给定T有效。


你可以和那些std::XXX_iterator玩类似的游戏。 没有任何东西可供std::ranges::size(启用sized_range)。

最新更新