当一个跨度是另一个跨度的子跨度时,C++ 是否允许在 std::span::iterators 之间进行比较?

Mak*_*ver 16 c++ language-lawyer c++20 std-span

一般来说,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!
}
Run Code Online (Sandbox Code Playgroud)

但是对于使用 创建的子跨度来说也是如此吗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;
}
Run Code Online (Sandbox Code Playgroud)

这会打印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;
}
Run Code Online (Sandbox Code Playgroud)

康桓瑋*_*康桓瑋 3

我认为标准不允许这样做。

根据[forward.iterators]中对Cpp17ForwardIterator的描述:

前向迭代器的域==是同一底层序列上的迭代器的域。

这意味着两个迭代器的相等和不等运算在相同的基础序列上定义。

在您的示例中,要比较的两个迭代器的基础序列是不同的,因为它们具有不同的起点和不同的大小,这使得当其中一个迭代器超出另一个序列的边界时,比较不再明确定义。


正如评论中提到的,您的示例将在 MSVC-STL 的调试模式下触发断言,维护者在#1435中对此进行了解释。Cpp 核心指南中也讨论了类似的问题,请参阅#1157