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

for*_*818 30 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;
}
Run Code Online (Sandbox Code Playgroud)

是否有可能阻止隐式转换?

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

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

我对C++ 11和pre C++ 11解决方案感兴趣,最好是两者兼容.

sky*_*ack 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;
}
Run Code Online (Sandbox Code Playgroud)

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

编辑

作为替代方案,根据OP在评论中的要求,与C++ 98一起使用的解决方案是声明为private构造函数获取int(long 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
}
Run Code Online (Sandbox Code Playgroud)

  • 只有在c ++ 11中才有可能,不是吗? (2认同)
  • @ tobi303 _"但是如果存在一个在pre c ++ 11和post c ++ 11中运行良好的解决方案,我更喜欢那个"_怎么样`private:Foo(int x);`? (2认同)

Bri*_*ian 26

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

Foo(int x) = delete;
Run Code Online (Sandbox Code Playgroud)

  • `Foo f(42)`将被禁止(即使'42`为正)(而'Foo f(42u)`也有效). (7认同)

Nat*_*dge 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?
                   ^
Run Code Online (Sandbox Code Playgroud)

如果您想要出错,请使用-Werror=sign-conversion.