In order to prevent "unexpected issues", with format specifies where types are defined in other modules, I'm looking for a cast operator which will fail to compile on a narrowing conversion: this represents a fundamental type error that needs to be addressed.
For example, a using in some external header that has recently been changed from a compatible type to an incompatible type:
namespace y {
using X = uint64_t; // "recent change", was previously int32_t
}
The goal is to get this to fail (error not warning-as-error), as the result is used as "%d
.
y::X a; // question covers ANY value in domain of X, not if overflow at run-time
int32_t r = cast_that_fails_to_compile_if_can_narrow<int32_t>(a);
// So this is guaranteed to always be a valid type specifier
// (per http://www.cplusplus.com/reference/cstdio/printf/)
// for the provided argument if the cast/code above compiles.
printf("%d", r);
(In this case the intractable narrowing issue should be handled by additional code changes.)
Initialization with braces (but not parentheses) disallows narrowing conversions:
int32_t r{a};
// or
int32_t r = {a};
// or
auto r = int32_t{a};
Your compiler may be allowing this anyway, but that is not standard-conform [1]. E.g. for GCC you need to add the -pedantic-errors
flag for it to actually generate a hard error.
Also note that the type for %d
should be int
. If you use int32_t
instead, you are risking a similar issue should a platform use a differently sized int
.
You can use it directly in the printf
call:
printf("%d", int{a});
[1] The standard always only requires compilers to print some diagnostic. It does not require hard errors preventing the compilation of the program. GCC for example only warns by-default, but that is still conforming.