为什么std::span缺少比较运算符?

21
std::span不是设计为轻量级引用std::vector/std::array/普通数组等的子区域吗?它的API中难道不应该包含比较运算符,以与它们保持一致吗?排除这些运算符背后的原因是什么?
注:这里的比较运算符指的是完整集合(<<=等)或者太空船运算符<=>

看起来 gsl::span 并没有包含这些内容,而 std::span 是从它版本化而来的。 - darune
2
@DanielLangr 为什么不像 std::vectorstd::array 一样进行字典比较呢?因为这些类型已经定义好了,所以为什么这里不这样做呢。 - Timo
2
请注意,P0122R7 提议为 span 引入比较运算符,但是当前的草案标准并未包含它。 - Daniel Langr
1
@darune gsl::span _确实_(而且一直都有)比较运算符。它们只是将它们移动到了它们自己的头文件中(https://github.com/microsoft/GSL/blob/master/include/gsl/span_ext)。 - Barry
1
普通数组显然没有这些比较(除了地址,由于容易引起混淆,<=> 在此排除)。 - Davis Herring
显示剩余3条评论
1个回答

11
正如Daniel Langr所指出的那样, std::span在其最初的提案P0122中具有比较运算符。然后,这些运算符在工作草案N4791中被删除,原因在P1085中说明。
简而言之,对于std::span,复制和const是“浅层的”(意味着复制一个std::span并不会复制其底层元素,并且const std::span不会阻止其底层元素被修改),因此,如果存在比较,则应该也是“浅层”的以保持一致性。
该论文给出了以下示例:
示例1:
T oldx = x;
change(x);
assert(oldx != x);
return oldx;

示例2:

void read_only(const T & x);

void f()
{
  T tmp = x;
  read_only(x);
  assert(tmp == x);
}

这些示例中的断言可能会失败,如果T = std::span,而对于常规类型则不会。
有人可能会认为std::string_view具有浅复制但深比较。P1085也对此进行了解释:
“这与string_view相匹配,但是string_view无法修改其指向的元素,因此string_view的浅复制可以被视为类似于写时复制优化。”

请注意,没有任何东西可以阻止字符数组的所有者在 std::string_view 指向它时修改原始存储。因此,例如 std::map<std::span<T>, U>std::map<std::string_view, U> 一样有问题。在我看来,std::string_view 也不应该包含比较运算符。 - user3624760
4
跟进:对于某些其他模板参数U,这两个示例都适用于T = std::span<const U>。难道对于这种情况,operator==不是合理的选择吗?是否也考虑过这种方法? - m8mble
5
span<const T>没有描述中的问题。 - Yakk - Adam Nevraumont
我们确实不希望在一个span上使用==来比较元素的值,考虑到std::span operator=的定义和std::span的基本意图。我不太明白为什么==被完全移除,而不是进行浅层比较==。这真的限制了这个类的实用性。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接