Search code examples
c++eigenc++20eigen3std-ranges

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


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!


Solution

  • 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()).