如何防止从int到unsigned int的隐式转换?

时间:2016-03-22 18:10:16

标签: c++ implicit-conversion unsigned-integer

假设你有这个:

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;
}

是否可以阻止隐式转化?

我能想到的唯一方法是explicilty提供一个带int的构造函数,如果int为负,会产生某种运行时错误,但如果我能得到它会更好这是一个编译器错误。

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

我对C ++ 11和pre C ++ 11解决方案感兴趣,最好是两种解决方案。

3 个答案:

答案 0 :(得分:29)

统一初始化可防止缩小。

它遵循(不按要求工作)示例:

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
}

答案 1 :(得分:27)

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

Foo(int x) = delete;

答案 2 :(得分:8)

如果您希望在每次出现此类代码时收到警告,并且您正在使用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