提问人:Maks Verver 提问时间:7/27/2023 最后编辑:DailyLearnerMaks Verver 更新时间:7/27/2023 访问量:374
当一个跨度是另一个跨度的子跨度时,C++ 是否允许在 std::span::迭代器之间进行比较?
Does C++ allow comparison between std::span::iterators when one span is a subspan of the other?
问:
一般来说,C++ 不允许比较不同容器之间的迭代器。例如:
int main() {
std::vector<int> v = {1, 2, 3};
std::vector<int> w = {4, 5, 6};
std::cout << v.end() == w.end() << std::endl; // undefined!
}
但是,对于使用 ?例如:std::span::subspan()
int main() {
int a[4] = { 1, 2, 3, 4};
std::span<int> s(a);
std::span<int> t = s.subspan(1, 2);
std::cout << t.begin() - s.begin() << std::endl;
}
这会打印,这是意料之中的,因为内部迭代器可能只是指向底层数组的指针。问题是:标准是否保证它正常工作?1
如果是这样,更一般地说,我是否可以比较来自内存中同一连续对象的任何跨度的迭代器?例如:
int main() {
int a[5] = { 1, 2, 3, 4, 5};
std::span<int> s(a);
std::cout << (s.subspan(1, 1).end() < s.subspan(3, 1).begin()) << std::endl;
}
答:
3赞
康桓瑋
7/27/2023
#1
我不认为标准允许这样做。
根据 [forward.iterators] 中 Cpp17ForwardIterator 的描述:
for 正向迭代器的域是 相同的基础序列。
==
这意味着两个迭代器的相等和不等式运算仅在相同的基础序列上定义。
在您的示例中,被比较的两个迭代器的基础序列是不同的,因为它们具有不同的起点和不同的大小,这使得当其中一个迭代器超出另一个序列的边界时,比较不再明确定义。
如评论中所述,您的示例将在 MSVC-STL 的调试模式下触发断言,维护者在 #1435 中对此进行了解释。CPP 核心指南中也讨论了类似的问题,请参阅 #1157。
评论
0赞
Weijun Zhou
7/27/2023
是否遇到与相同的问题?我不确定我是否应该问一个新问题,但偶尔我想问,当我知道这不等于潜在范围时。这是允许的吗?std::ranges::subrange
std::span::subspan
std::prev(subrange.begin())
subrange.begin()
begin()
1赞
康桓瑋
7/27/2023
我认为没关系,因为指定返回底层原始迭代器。原始迭代器上的操作的有效性不会改变。std::prev(subrange.begin())
subrange.begin()
1赞
Yakk - Adam Nevraumont
7/28/2023
“被比较的两个迭代器的基础序列是不同的”——这需要引用。这句话的措辞是,span 的基础序列仍然是原始缓冲区,span 本身的开始/结束是一个子序列。这将取决于标准的措辞方式。
1赞
康桓瑋
7/28/2023
@Yakk-AdamNevraumont:我不认为当前的标准明确定义了迭代器的基本序列是什么。在 C++17 中有一个:“当且仅当表达式 ++i
的应用序列有限,使 i == j 时,迭代器 j
才被称为可从迭代器 i
访问。如果 j
可以从 i
到达,它们指的是相同序列的元素“,但我认为在当前上下文中仍然可以以不同的方式解释它。
评论