I have code roughly equivalent, for all intents and purposes to the following:
#include <vector>
#include <iostream>
#include <algorithm>
int main() {
auto number = 2;
auto vec = std::vector<int>{1, 2, 3, 4};
auto number_location = std::find(vec.begin(), vec.end(), number);
auto number_index = std::distance(vec.begin(), number_location);
if (number_index + 3 >= vec.size()) {
std::cout << "Too close to the end\n";
}
return 0;
}
Where number
can be an arbirary integer. I believe that, since std:vector
is a random access container, std::distance
can potentially output a negative value, and the value deduced by auto
is, thus, signed, but for this specific code snippet it is guaranteed to always output a positive or zero value, no matter what value is given for number
. Since number_index is signed, when performing the comparison number_index + 2 > vec.size()
my compiler emits a warning (I'm compiling this with g++ 9.3, with flags -Wall -Wextra -Wpedantic -std=c++17
):
main.cpp: In function ‘int main()’:
main.cpp:10:24: warning: comparison of integer expressions of different signedness: ‘long int’ and ‘std::vector<int>::size_type’ {aka ‘long unsigned int’} [-Wsign-compare]
10 | if (number_index + 3 >= vec.size()) {
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
My question is: Is it a sound approach to do a static cast, maybe static_cast<long>(vec.size())
or static_cast<std::vector<int>::size_type>(number_index)
, or is there a better way to deal with code like this, where distances between unsigned values that "may in general be signed but for the case of interest are not signed" pop up?
If you know for sure that the value of the (formally) signed variable will not be negative, then the safest way to avoid the warning would be to cast that to a size_t
type, because unsigned types have a higher maximum value than signed types of the same size. Also, on most platforms, ptrdiff_t
(the deduced type of your number_index
) will be the same size as the size_t
type.
Casting an unsigned value to a signed type (of the same size) is less safe, as there is the possibility of overflow.
So, this would likely be a safe cast:
if (static_cast<size_t>(number_index) + 3 >= vec.size()) {
std::cout << "Too close to the end\n";
}