Is std::ranges::size supposed to return an unsigned integer?
Asked Answered
N

2

5

Here it is written that std::ranges::size should return an unsigned integer. However, when I use it on an Eigen vector (with Eigen 3.4) the following compiles:

Eigen::VectorXd x;
static_assert(std::same_as<Eigen::VectorXd::Index,
                           decltype(std::ranges::size(x))>);

where Eigen::VectorXd::Index is notoriously a signed integer. By looking at the implementation of std::ranges::size, I noticed that the return type is inferred from the return type of x.size(), which is precisely Eigen::VectorXd::Index. Is this a bug of std::ranges::size? Or is this expected?


Update 27/12/2021

The C++ reference page linked above has eventually changed the description of the std::ranges::size function: it only returns an integer, not necessarily an unsigned one!

Nostalgia answered 22/12, 2021 at 18:26 Comment(3)
A container's size() method is supposed to return an unsigned integer. The problem is at the Eigen's side.Papiamento
Otherwise, t.size() converted to its decayed type, if ranges::disable_sized_range<std::remove_cv_t<T>> is false, and the converted expression is valid and has an integer-like type. Looks like underspecified for containers which return signed types for sizes.Thurnau
When the call is valid, if no user-defined size() functions is involved, it returns an unsigned integer (or integer-class) value. Otherwise, it returns the return value of that size() function.Thuythuya
A
5

Is this a bug of std::ranges::size?

No. The cppreference documentation is misleading. There is no requirement for std::ranges::size to return an unsigned integer. In this case, it returns exactly what Eigen::VectorXd::size returns.

For ranges that model ranges::sized_range, that would be an unsigned integer, but Eigen::VectorXd evidently does not model such range.

But then what is the purpose of std::ranges::ssize compared to std::ranges::size?

The purpose of std::ranges::ssize is to be a generic way to get a signed value regardless of whether std::ranges::size returns signed or unsigned. There is no difference between them in cases where std::ranges::size returns a signed type.

Is there a reference to back up what you state?

Yes. See the C++ standard:

[range.prim.size]

Otherwise, if disable_­sized_­range<remove_­cv_­t<T>> ([range.sized]) is false and auto(t.size()) is a valid expression of integer-like type ([iterator.concept.winc]), ranges​::​size(E) is expression-equivalent to auto(​t.size()).

Archiepiscopal answered 22/12, 2021 at 18:48 Comment(6)
But then what is the purpose of std::ranges::ssize compared to std::ranges::size? Is there a reference to back up what you state?Nostalgia
Also, Eigen::VectorXd does satisfy the std::ranges::sized_range concept!Nostalgia
@Nostalgia See edited answer for your first comment. Eigen::VectorXd does satisfy the std::ranges::sized_range concept I disagree; It doesn't satisfy the requirements.Archiepiscopal
Actually it does: the only requirements to satisfy the std::ranges::sized_range concept are that Eigen::VectorXd is a range (which it is since Eigen 3.4) and that std::ranges::size can be called on Eigen::VectorXd objects.Nostalgia
To be fair, the cppreference documentation just mention that std::ranges::size() "Whenever ranges::size(e) is valid for an expression e, the return type is integer-like.", while std::ranges::ssize() "If ranges::ssize(e) is valid for an expression e, the return type is a signed-integer-like type, i.e. an integer type for which std::is_signed_v is true, or a signed-integer-class type. "Lovegrass
@Lovegrass Yeah, those are accurate. The misleading part is on the ranges library page linked in the question.Archiepiscopal
B
7

It's very much intended that the sized_range concept and the corresponding ranges::size customization point take no position on the signed/unsigned holy wars. ranges::size does convert to unsigned when computing from the distance between begin and end, for consistency with the existing standard library, but user types are not required to agree with that choice.

Blabbermouth answered 22/12, 2021 at 19:12 Comment(2)
Too bad, I feel it would be better if std::ranges::size always returned an unsigned integer and std::ranges::ssize always an unsigned one! Why not? What is the point?Nostalgia
@Nostalgia not part of standardization so IDK, but I guess maybe they did ranges before they agreed on ssizeEthelind
A
5

Is this a bug of std::ranges::size?

No. The cppreference documentation is misleading. There is no requirement for std::ranges::size to return an unsigned integer. In this case, it returns exactly what Eigen::VectorXd::size returns.

For ranges that model ranges::sized_range, that would be an unsigned integer, but Eigen::VectorXd evidently does not model such range.

But then what is the purpose of std::ranges::ssize compared to std::ranges::size?

The purpose of std::ranges::ssize is to be a generic way to get a signed value regardless of whether std::ranges::size returns signed or unsigned. There is no difference between them in cases where std::ranges::size returns a signed type.

Is there a reference to back up what you state?

Yes. See the C++ standard:

[range.prim.size]

Otherwise, if disable_­sized_­range<remove_­cv_­t<T>> ([range.sized]) is false and auto(t.size()) is a valid expression of integer-like type ([iterator.concept.winc]), ranges​::​size(E) is expression-equivalent to auto(​t.size()).

Archiepiscopal answered 22/12, 2021 at 18:48 Comment(6)
But then what is the purpose of std::ranges::ssize compared to std::ranges::size? Is there a reference to back up what you state?Nostalgia
Also, Eigen::VectorXd does satisfy the std::ranges::sized_range concept!Nostalgia
@Nostalgia See edited answer for your first comment. Eigen::VectorXd does satisfy the std::ranges::sized_range concept I disagree; It doesn't satisfy the requirements.Archiepiscopal
Actually it does: the only requirements to satisfy the std::ranges::sized_range concept are that Eigen::VectorXd is a range (which it is since Eigen 3.4) and that std::ranges::size can be called on Eigen::VectorXd objects.Nostalgia
To be fair, the cppreference documentation just mention that std::ranges::size() "Whenever ranges::size(e) is valid for an expression e, the return type is integer-like.", while std::ranges::ssize() "If ranges::ssize(e) is valid for an expression e, the return type is a signed-integer-like type, i.e. an integer type for which std::is_signed_v is true, or a signed-integer-class type. "Lovegrass
@Lovegrass Yeah, those are accurate. The misleading part is on the ranges library page linked in the question.Archiepiscopal

© 2022 - 2024 — McMap. All rights reserved.