如何解决contiguous_range始终是size_range吗?
关于C ++ 20中的范围库,我有以下问题:
让std::ranges::contiguous_range<T>
表示任意类型T。
我可以假设std::ranges::sized_range<T>
吗?
解决方法
不,并非每个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>);
,
由于存在前哨,因此成为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>>
is true. common_range<T>
means that is_same<iterator_t<T>,sentinel_t<T>>
。因此,random_access_iterator<sentinel_t<T>>
也必须为真。
现在,random_access_iterator<It>
imposes a requirement 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
的{{1}}有效。
ranges::size<T>
is valid,如果T
模型T
(确实如此)以及ranges::forward_range<T>
和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>>>;
};
,如您所见,它是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
)。
例如,您可能具有范围为范围的形式的无限数据流,即随机访问(您可以使用O(1)
跳到任何元素),但是鉴于数据是无限的,它不能是sized_range
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。