I wrote some program to test my suspicions. It contains super-ultra-reliable function, on my mind :)
, called less
to compare integral numbers. For some combinations of types it produces results that differ from the results, which gives C++. When this happens it gives false, that you can see on the screen.
#include <iostream>
#include <iomanip>
#include <type_traits>
#include <limits>
#include <typeinfo>
#include <cstdlib>
#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wtype-limits"
template< typename T, typename U >
inline
bool less(T const & lhs, U const & rhs)
{
if (std::is_signed< T >::value && std::is_unsigned< U >::value) {
if (lhs < 0) {
return true;
} else if (rhs > std::numeric_limits< T >::max()) {
return true;
} else {
return static_cast< T >(lhs) < rhs;
}
} else if (std::is_unsigned< T >::value && std::is_signed< U >::value) {
if (rhs < 0) {
return false;
} else if (lhs > std::numeric_limits< T >::max()) {
return false;
} else {
return lhs < static_cast< T >(rhs);
}
} else {
return lhs < rhs;
}
}
#pragma GCC diagnostic warning "-Wtype-limits"
#pragma GCC diagnostic warning "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wtype-limits"
template< typename U, typename S >
void test()
{
std::cout << typeid(U).name() << " vs " << typeid(S).name() << std::endl;
static_assert(std::is_unsigned< U >::value && std::is_signed< S >::value, "signedness violated");
static_assert(sizeof(U) != sizeof(S), "size should not be the same");
U const x(std::numeric_limits< U >::max() - 2);
S const y(-1);
S const z(std::numeric_limits< S >::min());
std::cout << std::boolalpha << (less(x, y) == (x < y)) << std::endl
<< std::boolalpha << (less(y, x) == (y < x)) << std::endl
<< std::boolalpha << (less(y, z) == (y < z)) << std::endl
<< std::boolalpha << (less(z, y) == (z < y)) << std::endl
<< std::boolalpha << (less(x, z) == (x < z)) << std::endl
<< std::boolalpha << (less(z, x) == (z < x)) << std::endl
<< std::endl;
}
#pragma GCC diagnostic warning "-Wtype-limits"
#pragma GCC diagnostic warning "-Wsign-compare"
int main()
{
using namespace std;
test< uint8_t, int16_t >();
test< uint8_t, int32_t >();
test< uint8_t, int64_t >();
test< uint16_t, int8_t >();
test< uint16_t, int32_t >();
test< uint16_t, int64_t >();
test< uint32_t, int8_t >();
test< uint32_t, int16_t >();
test< uint32_t, int64_t >();
test< uint64_t, int8_t >();
test< uint64_t, int16_t >();
test< uint64_t, int32_t >();
return EXIT_SUCCESS;
}
I compile (bash s.sh 2>&1 | tee s.log
) the program using the following script:
#!/usr/bin/env sh
set -o errexit
set -o verbose
g++ -std=gnu++11 -m64 s.cpp -o s64
g++ -std=gnu++11 -m32 s.cpp -o s32
MINGWDIR=/c/mingw64
PATH=/usr/bin:${MINGWDIR}/bin:/c/Windows/system32:${MINGWDIR}/x86_64-w64-mingw32/lib32 ./s64 2>&1 | tee s64.log | grep -c false
PATH=/usr/bin:${MINGWDIR}/bin:/c/Windows/system32:${MINGWDIR}/x86_64-w64-mingw32/lib32 ./s32 2>&1 | tee s32.log | grep -c false
diff s32.log s64.log
As a result (s.log
) script gives the following:
g++ -std=gnu++11 -m64 s.cpp -o s64
g++ -std=gnu++11 -m32 s.cpp -o s32
MINGWDIR=/c/mingw64
PATH=/usr/bin:${MINGWDIR}/bin:/c/Windows/system32:${MINGWDIR}/x86_64-w64-mingw32/lib32 ./s64 2>&1 | tee s64.log | grep -c false
10
PATH=/usr/bin:${MINGWDIR}/bin:/c/Windows/system32:${MINGWDIR}/x86_64-w64-mingw32/lib32 ./s32 2>&1 | tee s32.log | grep -c false
10
diff s32.log s64.log
As you can see the results are the same (for x32 and x64 platforms). And some of the tests have failed. Why is this happening? My program is wrong or my knowledge about C++ is little?