Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

replacing macro with a function causes "signed/unsigned mismatch" warning

For this snippet

   const std::vector<int> v;
   if (v.size() != 1) {} // could call operator!=()

the code complies cleanly even at high warnings levels (all warnings enabled in Visual Studio 2022). However, if I pass the arguments to a function

   const auto f = [](auto&& lhs, auto&& rhs) { if (lhs != rhs) {}};
   f(v.size(), 1);

the compiler generates a '!=': signed/unsigned mismatch warning.

How can I make the function behave the same way as the "inline" code, i.e., no warning?


Keep in mind that the "real code" is something like

#define f(lhs, rhs) if (lhs != rhs) {}

I'd like to "do the 'right thing'" and replace the macro with a function

temmplate<typename TLhs, typename TRhs>
inline void f(TLhs&& lhs, TRhs&& rhs)
{
   if (lhs != rhs) {}
}
like image 505
Jack Brown Avatar asked Dec 19 '25 02:12

Jack Brown


2 Answers

In the direct comparison the compiler knows the type of both side of the comparison, and can therefore make sure that the 1 will be an unsigned type of the correct size.

When you call your lambda the type for rhs will be deduced as an int, because that's what 1 really is. And since lhs will be an unsigned type, you get the warning in the comparison when you compare the unsigned size with the (signed) int value 1.


You will get the same problem with any kind of callable object where the compiler must deduce the arguments, like for example function templates:

template<typename T, typename U>
void f(T const& lhs, U const& rhs);

For a function template the solution is simple: Use the same single type for both arguments:

template<typename T>
void f(T const& lhs, T const& rhs);
like image 181
Some programmer dude Avatar answered Dec 20 '25 17:12

Some programmer dude


Move the problem out of your code by calling std::cmp_not_equal

const auto f = [](auto&& lhs, auto&& rhs) {
     if (std::cmp_not_equal(lhs, rhs)) { blah blah }
};

This family of functions, added in C++20, is defined in a way that properly compares integer arguments even in the presence of a signed/unsigned mismatch.

Now the Standard library author is responsible for writing "all that template gunk" and all you need to do extra is #include <utility>


For the specific case of assertions, you need a macro anyway to capture information.

#define ASSERT_EQ(actual, expected) do { \
      if (lhs == rhs) break; \
      log_assertion_failure(__FILE__, __LINE__, #actual, actual, expected); \
  } while(0)
like image 32
Ben Voigt Avatar answered Dec 20 '25 17:12

Ben Voigt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!