如何防止从 int 到无符号 int 的隐式转换

How to prevent implicit conversion from int to unsigned int?

本文关键字:int 转换 何防止 无符号      更新时间:2023-10-16

>假设你有这个:

struct Foo {
    Foo(unsigned int x) : x(x) {}
    unsigned int x;
};
int main() {
    Foo f = Foo(-1);     // how to get a compiler error here?
    std::cout << f.x << std::endl;
}

是否可以阻止隐式转换?

我能想到的唯一方法是显式提供一个构造函数,该构造函数采用int并在int为负时生成某种运行时错误,但如果我可以为此得到编译器错误会更好。

我几乎可以肯定,有一个重复项,但我能找到的最接近的是这个问题,而是问为什么允许隐式转换。

我对 C++11 和 C++11 之前的解决方案都感兴趣,最好是同时适用于两者的解决方案。

统一初始化可防止缩小范围。

它遵循一个(根据要求不起作用)示例:

struct Foo {
    explicit Foo(unsigned int x) : x(x) {}
    unsigned int x;
};
int main() {
    Foo f = Foo{-1};
    std::cout << f.x << std::endl;
}

只要尽可能习惯使用统一初始化(Foo{-1}而不是Foo(-1))。

编辑

作为替代方案,正如 OP 在注释中要求的那样,也适用于 C++98 的解决方案是声明为private构造函数获得intlong int 等)。
实际上没有必要定义它们。
请注意,正如另一个答案中所建议的那样,= delete也是一个很好的解决方案,但这也是自 C++11 以来的解决方案。

编辑 2

我想再添加一个解决方案,尽管它自 C++11 起有效。
这个想法是基于Voo的建议(有关更多详细信息,请参阅Brian的回应评论),并在构造函数的参数中使用SFINAE。
它遵循一个最小的工作示例:

#include<type_traits>
struct S {
    template<class T, typename = typename std::enable_if<std::is_unsigned<T>::value>::type>
    S(T t) { }
};
int main() {
    S s1{42u};
    // S s2{42}; // this doesn't work
    // S s3{-1}; // this doesn't work
}

您可以通过删除不需要的重载来强制编译错误。

Foo(int x) = delete;
如果您希望在

每次出现此类代码时收到警告,并且您使用的是 GCC,请使用 -Wsign-conversion 选项。

foo.cc: In function ‘int main()’:
foo.cc:8:19: warning: negative integer implicitly converted to unsigned type [-Wsign-conversion]
     Foo f = Foo(-1);     // how to get a compiler error here?
                   ^

如果需要错误,请使用 -Werror=sign-conversion