Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparison between signed and unsigned. Is static_cast the only solution?

I use third party containers that use int to store the size. I also use stl containers which use size_t to store size.

I very often in my code have to use both in the same loop, like for example:

// vec is std::vector
// list is the third party container
assert(vec.size() == list.size()); // warning
for(size_t i = 0; i < vec.size(); i++)
{
    vec[i] = list[i]; // warning
}

So to fix I have to either I do function style casting, which I was told is C style casting in disguise.

// vec is std::vector
// list is the third party container
assert(int(vec.size()) == list.size());
for(size_t i = 0; i < vec.size(); i++)
{
    vec[i] = list[int(i)];
}

Or I can do the even uglier solution that everyone recommends. The static casting.

// vec is std::vector
// list is the third party container
assert(static_cast<int>(vec.size()) == list.size());
for(size_t i = 0; i < vec.size(); i++)
{
    vec[i] = list[static_cast<int>(i)];
}

I really don't want to static_cast.

  • Can the implicit conversion in this particular scenario be dangerous?
  • Would the function style be okay in my case?
  • If static_cast is really the only safe solution. Should I cast the int to size_t or size_t to int?

Thank you.

like image 455
Adham Zahran Avatar asked Oct 16 '22 10:10

Adham Zahran


1 Answers

Binary operators (operator== here) convert signed integers to unsigned if one of the arguments is unsigned. A signed negative integer turns into a big positive one.

Container element count must not be negative to avoid breaking the principle of least surprise. So, the implicit conversion must be safe. But be sure to check the implementation/documentation of int size() const.

You may like to preserve the semantics of the implicit conversion and use as_unsigned function to avoid the cast and better convey the intent:

#include <type_traits>

template<class T>
inline typename std::make_unsigned<T>::type as_unsigned(T a) {
    return static_cast<typename std::make_unsigned<T>::type>(a);
}

and then:

assert(vec.size() == as_unsigned(list.size()));
like image 185
Maxim Egorushkin Avatar answered Oct 21 '22 04:10

Maxim Egorushkin