In the example below, if I don't cast 4 as unsigned I get a warning about '<=' signed/unsigned mismatch in default.hpp(144) followed by many more warning I don't follow.
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <string>
namespace qi = boost::spirit::qi;
typedef std::wstring::const_iterator it_type;
int main()
{
using qi::_1;
using boost::spirit::_pass;
std::wstring testChar(L"450");
auto f = testChar.begin(), l = testChar.end();
unsigned pVal[2] = {0, 0};
qi::uint_parser<unsigned, 10, 1, 1> uint1_p;
bool retVal = qi::parse(f, l, uint1_p[_pass = _1 <= (unsigned)4] >> qi::uint_, pVal[0], pVal[1]);
return 0;
}
Is it just best to always cast in this case?
Building on Visual Studio 2015 with Boost 1.61.0
You're comparing the attribute of the uint1_p
parser to 4
. The attribute type of uint1_p{}
is unsigned
, so you're comparing unsigned
with decltype(4)
, which is int
.
Doing mixed-sign comparisons is dangerous and the compiler warns about that. The problem is that unsigned integer arithmetic is "contagious", meaning that the 4
will be promoted to unsigned, not the other way around. This is a risk if you had e.g. _1 >= 0
because it could never be false.
The impressive "error novel" is because the warning arises deep inside the Spirit code for semantic action evaluation. You would have the same message if you wrote something much simpler, like e.g.:
#include <iostream>
int main() {
for (unsigned i = 10; i >= 0; --i)
std::cout << i << " ";
}
This program does not stop after 10 iterations. And the compiler (in this case, GCC) warns:
prog.cc:3:29: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits]
for (unsigned i = 10; i >= 0; --i)
~~^~~~
Q. SHOULD I ALWAYS CAST?
Yes. And no. You should never use the C-style cast you wrote¹. You could consider static_cast<unsigned>(4)
. But I'd simply write 4u
:
bool retVal = qi::parse(f, l, uint1_p[_pass = (_1 <= 4u)] >> qi::uint_, pVal[0], pVal[1]);
¹ See e.g.