Is there a way to persuade a good C++ compiler to warn about the overflow in constructing a user defined type from a user defined literal as shown in the example code below? At least (via Godbolt) GCC and Clang warn about the overflow in the equivalent intrinsic code, but MSVC doesn't. None care about the same error in the user defined code.
#include <iostream>
struct MyShort
{
short data;
constexpr MyShort ( short arg ) : data ( arg ) {}
};
constexpr MyShort operator "" _MyShort ( unsigned long long arg )
{
return MyShort ( arg );
}
struct UseMyShort
{
MyShort constexpr static var1 = 100000_MyShort;
short constexpr static var2 = 100000;
};
int main ( int argc, char** argv )
{
std::cout << UseMyShort::var1.data;
std::cout << UseMyShort::var2;
}
UPDATE: Thanks pyj and cigien. You gave me the clue. When the code is run at compile time, the compiler doesn't care about branches not taken, so non-constexpr expressions are fine. If the compiler executes that path it errors which is the desired outcome. I have adapted your solutions to assert so the code also detects runtime errors when in debug mode. Updated code below. I've accepted cigien's answer because it looks like they took a penalty for a faulty draft, not a faulty idea.
#include <iostream>
#include <limits>
#include <assert.h>
template <class elem>
constexpr elem rangeCheck ( unsigned long long arg )
{
if ( arg > std::numeric_limits<elem>::max() ) {
assert ( false );
}
return elem(arg);
}
struct MyShort
{
short data;
constexpr MyShort ( short arg ) : data ( arg ) {}
};
constexpr MyShort operator "" _MyShort ( unsigned long long arg )
{
return MyShort { rangeCheck<short> (arg) };
}
struct UseMyShort
{
// compile time error (GCC):-
// ... call to non-constexpr function ‘void __assert_fail(const char*, const char*, unsigned int, const char*)’
// assert ( false );
// ^
MyShort constexpr static var1 = 100000_MyShort;
short constexpr static var2 = 100000; // compile time warning (with GCC -Woverflow)
};
int main ( int, char** )
{
std::cout << UseMyShort::var1.data;
std::cout << UseMyShort::var2;
MyShort const var4 = 100000_MyShort; // runtime error
MyShort var5 = 100000_MyShort; // runtime error
return 0;
}