0

为了防止“意外问题”,使用格式指定在其他模块中定义类型的位置,我正在寻找一个转换运算符,它在缩小转换时将无法编译:这表示需要解决的基本类型错误。

例如,在最近从兼容类型更改为不兼容类型的某些外部标头中使用:

 namespace y {
   using X = uint64_t; // "recent change", was previously int32_t
 }

目标是让它失败(错误不是警告作为错误),因为结果用作"%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);

(在这种情况下,棘手的缩小问题应该通过额外的代码更改来处理。)

4

2 回答 2

4

用大括号(但不是括号)初始化不允许缩小转换:

int32_t r{a};
// or
int32_t r = {a};
// or
auto r = int32_t{a};

无论如何,您的编译器可能都允许这样做,但这不符合标准[1]。例如,对于 GCC,您需要为其添加-pedantic-errors标志以实际生成硬错误。

还要注意 for 的类型%d应该是int. 如果您int32_t改为使用,如果平台使用不同大小的int.

您可以直接在printf调用中使用它:

printf("%d", int{a});

[1] 该标准始终只要求编译器打印一些诊断信息。它不需要阻止程序编译的硬错误。例如,GCC 仅在默认情况下发出警告,但这仍然符合要求。

于 2019-12-15T22:02:14.193 回答
1

可以使用模板函数来检查缩小强制转换,但允许其他静态强制转换:

template <typename Tto, typename Tfr>
Tto static_cast_prohibit_narrow(Tfr v)
{
    static_assert(sizeof(Tfr) <= sizeof(Tto), "Narrowing cast prohibited");
    return static_cast<Tto>(v);
}

编译器在允许其他 static_casts 时遇到窄转换时产生错误。

int main()
{
    long long int i1{ 4 };
    int i2{ 5 };
    //i2 = static_cast_prohibit_narrow<int>(i1); // Compiler static_assert error
    i1 = static_cast_prohibit_narrow<int>(i2);
}
于 2019-12-15T23:25:35.493 回答