Search code examples
c++castingc++14type-safetynarrowing

Cast and Fail Compilation if a narrowing conversion is possible


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.)


Solution

  • 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.