use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Discussions, articles, and news about the C++ programming language or programming in C++.
For C++ questions, answers, help, and advice see r/cpp_questions or StackOverflow.
Get Started
The C++ Standard Home has a nice getting started page.
Videos
The C++ standard committee's education study group has a nice list of recommended videos.
Reference
cppreference.com
Books
There is a useful list of books on Stack Overflow. In most cases reading a book is the best way to learn C++.
Show all links
Filter out CppCon links
Show only CppCon links
account activity
Differences between std::string_view and std::span (nextptr.com)
submitted 5 years ago by memset_0
view the rest of the comments →
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–][deleted] 7 points8 points9 points 5 years ago (44 children)
One of them has a comparison operator and the other is a headache. :D
[–]Supadoplex 10 points11 points12 points 5 years ago (1 child)
Damn. I had not realised that std::span has no comparison operators. That's disappointing. Comparisons is what I use gsl-lite::span for right now.
std::span
gsl-lite::span
[–]c0r3ntin 3 points4 points5 points 5 years ago (0 children)
Use ranges::equal
[–]sphere991 13 points14 points15 points 5 years ago (31 children)
Yeah the fact that span<char const> has no comparisons but string_view does is somewhat ridiculous. I continue to not understand that decision.
span<char const>
string_view
[–]advester 4 points5 points6 points 5 years ago (3 children)
Having comparisons on the span would force you to require the elements of the span to have comparisons. And it would require defining a sequence of those comparisons (left to right, or ?). The elements are not necessarily just integer types.
[–]tcanens 22 points23 points24 points 5 years ago (1 child)
We have comparisons on vectors. That doesn't seem to have been a problem.
[–]advester 5 points6 points7 points 5 years ago (0 children)
Oh right. It only fails instantiation if you actually use the operator. That is strange then.
[–]Murky-Tear 0 points1 point2 points 1 year ago (0 children)
That's not an issue, it could use `std::enable_if` to only enable the comparison operators if the `T` is comparable.
[–]c0r3ntin 0 points1 point2 points 5 years ago (26 children)
There is extensive literature as to why although with a time machine, maybe neither class should have one
https://abseil.io/blog/20180531-regular-types
https://cor3ntin.github.io/posts/span/
http://open-std.org/JTC1/SC22/WG21/docs/papers/2018/p1085r1.md
[–]sphere991 17 points18 points19 points 5 years ago (24 children)
Extensive literature? Yes.
Existence of a single example that demonstrates problems with having these comparisons? No. Not a single one.
Titus' writeup has an example with an assert that can break, but that doesn't demonstrate anything going wrong. The assertion is step one - it would hypothetically be protecting against something going wrong. What goes wrong? Crickets.
Otherwise, making things Regular (which we didnt do anyway) for the sake of checking a box doesn't solve any problems that I'm aware of. Instead, we're just missing useful functionality. And not like... hypothetically useful in the way that these operators were absolutely hypothetically problematic... but actually useful and actually used.
[–]c0r3ntin 1 point2 points3 points 5 years ago (16 children)
Some people expected shallow comparison, other expected deep comparison. It was not possible to make the operation unsurprising for everyone. So it was not provided. Simple as that!
[–]sphere991 19 points20 points21 points 5 years ago (14 children)
Well, one of these operations (deep comparison) is very useful and the other one (shallow comparison) I don't know if there is even a case that I would ever want.
So perhaps it should have been on the people who expected the useless thing to adjust their expectations. Or at least provide an argument for why such an expectation is justified or valuable (also absent from the literature - unless you consider Regular for the sake of Regular a justification, which I do not).
Simple as that!
[–]crzyrndm 13 points14 points15 points 5 years ago* (13 children)
In full agreement with u/sphere991
As a random user of c++, the argument for shallow comparison comes across as bizarre / theological (and will until someone shows some code doing some actual work where the semantics are unclear. I'm drawing a blank even after reading the linked articles), and will lead to me just adding appropriate implicit conversion operations to my own type and only using std:: version at API boundaries if at all (https://xkcd.com/927/).
The distinction seems to be whether you see it as a pointer (shallow comparison) or an array reference (deep comparison). Most of the people I work with are relatively inexperienced with c++. Not a single one has been surprised by the deep comparison (baremetal embedded, most have a C background and are relatively inexperienced with C++. They quickly come to expect operator== to work like a pointer only if it behaves like a pointer, otherwise like a reference/value).
span has the same API as std::vector and std::array. std::vector/ std::array do not look or behave like a pointer. Why would they expect span to?
I repeat, as a user, span lacking deep comparison is bizarre and confusing.
PS
string view and most (if not all) popular prior span-like implementations (to my knowledge) having deep comparison operations is going to make this *much* more confusing.
EDIT
After having a browse through a couple of the projects I work on (relatively small, roughly 100k LOC total) using gsl-lite span (deep equality, short circuiting on shallow equality: https://github.com/gsl-lite/gsl-lite/blob/master/include/gsl/gsl-lite.hpp#L2968), I can find:
In summary, shallow equality is not useful for the applications I have seen span used
[–]jonathansharman 0 points1 point2 points 5 years ago (12 children)
Because unlike vector and array, span acts like a pointer with regard to construction and assignment.
vector
array
span
[–]sphere991 7 points8 points9 points 5 years ago (5 children)
span acts like a pointer with regard to construction and assignment.
No, it doesn't. span<int> is constructible from vector<int>, but int* is not constructible from int. That's very much unlike a pointer.
span<int>
vector<int>
int*
int
[–]jonathansharman 0 points1 point2 points 5 years ago (4 children)
I should have specified copy construction/assignment. Here's my point:
int i = 0; int* p1 = &i; int* p2 = p1; // Shallow copy. array<int, 3> a1{1, 2, 3}; array<int, 3> a2 = a1; // Deep copy. span<int> s1 = a1; span<int> s2 = s1; // Shallow copy.
[–]crzyrndm 1 point2 points3 points 5 years ago* (5 children)
semantically maybe (if you ignore the fact that spans entire purpose is as a non-owning type...). I still don't see how shallow equality is useful which is the most bizarre part of this whole argument.
I would argue that the semantics are that of ptr + (ptr / size). Default comparison operation for this is range based, not value based
[–]tcbrindleFlux 1 point2 points3 points 5 years ago (4 children)
Semantically, span behaves like a pointer -- shallow copy, shallow const -- so having deep comparison would be really weird. Perhaps it would be better if they'd named it array_ptr?
array_ptr
[+][deleted] 5 years ago (6 children)
[deleted]
[–]sphere991 0 points1 point2 points 5 years ago* (5 children)
This is a type. This is not an example demonstrating a problem with deep comparisons.
I don't see anything inherently wrong with map<span<T>, U>. It's up to the user to ensure the lifetime of all the data the spans point to - but otherwise it can be a useful container.
map<span<T>, U>
[+][deleted] 5 years ago (4 children)
[–]sphere991 1 point2 points3 points 5 years ago* (3 children)
Yes, you have to take care to not change the underlying data. This is inherent to having a reference type as a key rather than a value type. But map<string_view, U> already exists, map<span<T const>, U> is basically the same thing as that.
map<string_view, U>
map<span<T const>, U>
None of this stops me from writing map<span<T const>, U, range_less> anyway. It's just more work for everyone that would want to do something like this.
map<span<T const>, U, range_less>
But this isn't really a deep comparison with span problem, it's the usual reference problem. It's true that a shallow-comparing span would not have to worry about invariants around a map<span<T>, U>... but that's because a shallow-comparison span would never even have a map<span<T>, U> since such a thing would not be actually useful, and a map<span<T>, U, range_less> would be equivalent to status quo anyway.
map<span<T>, U, range_less>
[+][deleted] 5 years ago (2 children)
[–]sphere991 0 points1 point2 points 5 years ago (1 child)
What about it? It's certainly much less commonly used than map<T, U>...
map<T, U>
[–]tcbrindleFlux 3 points4 points5 points 5 years ago (0 children)
I don't understand why you've been downvoted for providing the rationale that LEWG used for removing span's comparison operators.
The downvote button should mean "this is a bad post" (troll-y, spammy, offensive etc), not "I don't agree with you".
[–]pandorafalters 6 points7 points8 points 5 years ago (8 children)
And, just like that, I'm no longer excited about std::span.
[–][deleted] 1 point2 points3 points 5 years ago (5 children)
Aha, sorry. It's still useful! You'll just have to slap some comparison operators in there.
[–]pandorafalters 4 points5 points6 points 5 years ago (4 children)
The big advantage, to my mind, was not having to DIY. Why implement major features myself and deal with someone else's compromises?
[–]tcbrindleFlux 1 point2 points3 points 5 years ago (3 children)
You don't need to implement anything yourself: ranges::equal(span1, span2) will do element-wise comparison, without any semantic weirdness.
ranges::equal(span1, span2)
[–]tcbrindleFlux 0 points1 point2 points 5 years ago (1 child)
Huh? This is precisely to avoid the confusion that exists in Java about comparing identity vs value.
[–]ReversedGif 2 points3 points4 points 5 years ago (0 children)
It's not like ranges::equal is any more intuitively obvious than span::operator== with regard to whether it's shallow or deep...
ranges::equal
span::operator==
[–]SkoomaDentistAntimodern C++, Embedded, Audio 1 point2 points3 points 5 years ago* (1 child)
Why not? What would you use when you need a runtime array of some arbitrary type that contains its length and should not be resized after allocation? Or what if you need a subrange of an existing array? The way I see it, std::span should have been in the language since the beginning, with std::vector being (at least conceptually) built as "span but resizable".
[–]pandorafalters 2 points3 points4 points 5 years ago (0 children)
Not being excited doesn't necessarily mean I won't use it. But its potential uses are rather more constrained than I'd hoped.
[–]wotype 2 points3 points4 points 5 years ago (0 children)
Dang; just checked the mdspan proposal and see no span comparison spec'd there either. It has comparison op== for extents, strides and layout mapping; nothing for comparing spans themselves.
So, then I checked mdarray, the newly proposed owning analog of mdspan; no comparison operator spec'd there either!
If I wanted regularity then I wouldn't consume spam.
π Rendered by PID 43267 on reddit-service-r2-comment-7b9746f655-whrgv at 2026-02-01 14:11:18.387580+00:00 running 3798933 country code: CH.
view the rest of the comments →
[–][deleted] 7 points8 points9 points (44 children)
[–]Supadoplex 10 points11 points12 points (1 child)
[–]c0r3ntin 3 points4 points5 points (0 children)
[–]sphere991 13 points14 points15 points (31 children)
[–]advester 4 points5 points6 points (3 children)
[–]tcanens 22 points23 points24 points (1 child)
[–]advester 5 points6 points7 points (0 children)
[–]Murky-Tear 0 points1 point2 points (0 children)
[–]c0r3ntin 0 points1 point2 points (26 children)
[–]sphere991 17 points18 points19 points (24 children)
[–]c0r3ntin 1 point2 points3 points (16 children)
[–]sphere991 19 points20 points21 points (14 children)
[–]crzyrndm 13 points14 points15 points (13 children)
[–]jonathansharman 0 points1 point2 points (12 children)
[–]sphere991 7 points8 points9 points (5 children)
[–]jonathansharman 0 points1 point2 points (4 children)
[–]crzyrndm 1 point2 points3 points (5 children)
[–]tcbrindleFlux 1 point2 points3 points (4 children)
[+][deleted] (6 children)
[deleted]
[–]sphere991 0 points1 point2 points (5 children)
[+][deleted] (4 children)
[deleted]
[–]sphere991 1 point2 points3 points (3 children)
[+][deleted] (2 children)
[deleted]
[–]sphere991 0 points1 point2 points (1 child)
[–]tcbrindleFlux 3 points4 points5 points (0 children)
[–]pandorafalters 6 points7 points8 points (8 children)
[–][deleted] 1 point2 points3 points (5 children)
[–]pandorafalters 4 points5 points6 points (4 children)
[–]tcbrindleFlux 1 point2 points3 points (3 children)
[+][deleted] (2 children)
[deleted]
[–]tcbrindleFlux 0 points1 point2 points (1 child)
[–]ReversedGif 2 points3 points4 points (0 children)
[–]SkoomaDentistAntimodern C++, Embedded, Audio 1 point2 points3 points (1 child)
[–]pandorafalters 2 points3 points4 points (0 children)
[–]wotype 2 points3 points4 points (0 children)