The code below
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v = { 1,2,3 };
if (std::count(v.begin(), v.end(), 1) > v.size() / 2) {
std::cout << "Too many\n";
}
}
gives a warning:
(8,40) warning C4018: '>': signed/unsigned mismatch
which is quite reasonable, since std::count returns ::difference_type
and size() returns ::size
.
The question is, what is the robust way to handle this?
In the Comparing ptrdiff_t with size_t it is discussed how this should be implemented in compilers, but never said how to safely live with existing implementations.
For example, it is stated:
If
ptrdiff_t
is of greater rank thansize_t
and can represent all positive values ofsize_t
.limit - buf <= sizeof buf
poses no problems then.
Else
ptrdiff_t
may not represent all positive values ofsize_t
and then the subtractionlimit - buf
may be UB per below, so the compare is moot.
Great, but under Win64 we have:
typedef unsigned __int64 size_t;
typedef __int64 ptrdiff_t;
And this is a direct indications (if containers don't use other types for ::difference_type) that size_t
values won't fit to ptrdiff_t
for safe calculations (it can't represent all size_t values as positive).
So, this:
if (std::count(v.begin(), v.end(), 1) > static_cast<std::vector<int>::difference_type>(v.size() / 2)) {
std::cout << "Too many\n";
}
is not safe anymore.
Casting in the opposite way is unacceptable since it violates first guidance above.
So, what is the safest way to shape the code here?
Should I write a wrapper to check the sizes and return the largest type or there is something more reasonable and built-in?
The issue is between a signed and unsigned integer value. Vector
does not have an unsigned ssize
function. Instead, use the ssize()
from the standard or ranges library.
auto main() -> int {
std::vector<int> v = { 1,2,3 };
if (std::count(v.begin(), v.end(), 1) > std::ssize(v) / 2) {
std::cout << "Too many\n";
}
return 0;
}