21

Wasn't the std::span designed as a lightweight reference to sub-regions of std::vector/std::array/plain array and alike? Shouldn't it also contain comparison operators in its API, to be consistent with them? What was the reasoning behind the exclusion?

Note: by comparison operators, I mean either the full set (<, <=, ...) or the spaceship <=>

xskxzr
  • 12,442
  • 12
  • 37
  • 77
GreenScape
  • 7,191
  • 2
  • 34
  • 64
  • Great question IMO, Im wondering the same. `operator==` is also missing. Esp. for vector I often find it convenient to compare directly. It could be due to difficulties perhaps with the static size span types, although Im not sure. – darune Mar 11 '20 at 10:27
  • It looks like gsl::span, from which std::span is versioned from doesn't include these either. – darune Mar 11 '20 at 10:30
  • The problem might be in the _element-comparison operator_. How should it be defined? Hard-coding `operator<` or `std::less` likely would not be the best approach. A template argument of `std::span`? How should it be defined for non-comparable value types? Template argument of a span comparison operator? Note that, e.g., `std::string_view` has _character traits_ for this purpose. – Daniel Langr Mar 11 '20 at 10:36
  • 2
    @DanielLangr why not a lexicographical comparison like `std::vector` and `std::array` do? They're defined just like that for those types already, so why not here. – Timo Mar 11 '20 at 10:39
  • @Time You're right, it would likely work. It basically works as `std::lexicographical_compare`, which uses `operator<` by default. – Daniel Langr Mar 11 '20 at 10:42
  • 2
    Note that [P0122R7](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0122r7.pdf) proposes comparison for `span`, but the [current draft standard](http://eel.is/c++draft/views) does not include it. – Daniel Langr Mar 11 '20 at 10:50
  • 1
    @darune `gsl::span` _does_ (and always did) have comparison operators. They just moved them into their [own header](https://github.com/microsoft/GSL/blob/master/include/gsl/span_ext) – Barry Mar 11 '20 at 13:52
  • 1
    Plain arrays certainly do not have these comparisons (except by address, which `<=>` excludes for being confusing). – Davis Herring Mar 12 '20 at 00:06

1 Answers1

11

As Daniel Langr pointed out, std::span has comparison operators in its initial proposal P0122. These operators are then removed since the working draft N4791, and the reasons are stated in P1085.

In short, copy and const for std::span are "shallow" (meaning copying a std::span doesn't copy its underlying elements, and a const std::span doesn't prevent its underlying elements from being modified), so comparisons, if exist, should also be "shallow" for consistency.

That paper gives the following examples:

Example 1:

T oldx = x;
change(x);
assert(oldx != x);
return oldx;

Example 2:

void read_only(const T & x);

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

The assertions in these examples may fail if T = std::span, while it doesn't for regular types.

One may argue that std::string_view has shallow copy but deep comparisons. P1085 also has an explanation for this:

This matches string_view, however string_view can't modify the elements it points at, and thus the shallow copy of string_view can be thought of as similar to a copy-on-write optimization.

xskxzr
  • 12,442
  • 12
  • 37
  • 77
  • Note that nothing prevents the owner of character array to modify the original storage while `std::string_view` points to it. So, say, `std::map, U>` is as broken as `std::map`. IMHO, `std::string_view` shouldn't contain comparison operators either. –  Mar 18 '20 at 06:54
  • 3
    Follow up: Both examples would work for `T = std::span` for some other template parameter `U`. Wouldn't `operator==` be reasonable for this case? Has this been considered as well? – m8mble Jun 14 '21 at 14:04
  • 4
    A `span` does not have the described problem. – Yakk - Adam Nevraumont Jul 21 '21 at 23:54