如何防止从 int 到 unsigned int 的隐式转换?
How to prevent implicit conversion from int to unsigned int?
假设你有这个:
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
为负数时生成某种运行时错误,但如果我这样做会更好可能会出现编译器错误。
我几乎可以肯定,存在重复,但我能找到的最接近的是 this question,它询问为什么允许隐式转换。
我对 C++11 和 C++11 之前的解决方案都感兴趣,最好是能同时适用于两者的解决方案。
您可以通过删除不需要的重载来强制编译错误。
Foo(int x) = delete;
统一初始化防止缩小。
它遵循一个(不工作,按要求)示例:
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
构造函数获得 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
}
如果您希望在 每次 出现此类代码时收到警告,并且您使用的是 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
。
假设你有这个:
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
为负数时生成某种运行时错误,但如果我这样做会更好可能会出现编译器错误。
我几乎可以肯定,存在重复,但我能找到的最接近的是 this question,它询问为什么允许隐式转换。
我对 C++11 和 C++11 之前的解决方案都感兴趣,最好是能同时适用于两者的解决方案。
您可以通过删除不需要的重载来强制编译错误。
Foo(int x) = delete;
统一初始化防止缩小。
它遵循一个(不工作,按要求)示例:
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
构造函数获得 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
}
如果您希望在 每次 出现此类代码时收到警告,并且您使用的是 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
。