简体   繁体   English

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

[英]How to prevent implicit conversion from int to unsigned int?

Suppose you have this: 假设你有这个:

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

Is it possible to prevent the implicit conversion? 是否有可能阻止隐式转换?

The only way I could think of is to explicilty provide a constructor that takes an int and generates some kind of runtime error if the int is negative, but it would be nicer if I could get a compiler error for this. 我能想到的唯一方法是explicilty提供一个构造函数,它接受一个int并在int为负数时生成某种运行时错误,但如果我为此得到编译器错误会更好。

I am almost sure, that there is a duplicate, but the closest I could find is this question which rather asks why the implicit conversion is allowed. 我几乎可以肯定,有一个重复,但我能找到的最接近的是这个问题 ,而不是为什么允许隐式转换。

I am interested in both, C++11 and pre C++11 solutions, preferably one that would work in both. 我对C ++ 11和pre C ++ 11解决方案感兴趣,最好是两者兼容。

Uniform initialization prevents narrowing. 统一初始化可防止缩小。

It follows a (not working, as requested) example: 它遵循一个(不工作,如请求)示例:

struct Foo {
    explicit Foo(unsigned int x) : x(x) {}
    unsigned int x;
};

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

Simply get used to using the uniform initialization ( Foo{-1} instead of Foo(-1) ) wherever possible. 只要有可能,只需习惯使用统一初始化( Foo{-1}而不是Foo(-1) )。

EDIT 编辑

As an alternative, as requested by the OP in the comments, a solution that works also with C++98 is to declare as private the constructors getting an int ( long int , and so on). 作为替代方案,正如OP在评论中所要求的那样,同样适用于C ++ 98的解决方案是将构造函数声明为private ,获取intlong int ,依此类推)。
No need actually to define them. 不需要实际定义它们。
Please, note that = delete would be also a good solution, as suggested in another answer, but that one too is since C++11. 请注意, = delete也是一个很好的解决方案,正如另一个答案中所建议的那样,但是自从C ++ 11以来也是如此。

EDIT 2 编辑2

I'd like to add one more solution, event though it's valid since C++11. 我想添加一个解决方案,虽然它自C ++ 11以来是有效的。
The idea is based on the suggestion of Voo (see the comments of Brian's response for further details), and uses SFINAE on constructor's arguments. 这个想法是基于Voo的建议(请参阅Brian的回复的评论以获得更多细节),并在构造函数的参数上使用SFINAE。
It follows a minimal, working example: 它遵循一个最小的工作示例:

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

If you want to be warned on every occurrence of such code, and you're using GCC, use the -Wsign-conversion option. 如果您希望在每次出现此类代码时收到警告,并且您正在使用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?
                   ^

If you want an error, use -Werror=sign-conversion . 如果您想要出错,请使用-Werror=sign-conversion

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM