在模板 class 中时枚举中出现整数溢出
Integer overflow in enum when in template class
深入研究模板元编程,我发现了 C++ 中枚举范围的奇怪行为。我收到 警告:表达式 中的整数溢出,看起来我实际上不想要超出枚举范围的值。这是代码:
#include <iostream>
#include <limits>
template <int i>
class pow {
public:
enum { result = 2*pow<i-1>::result};
};
template<>
class pow<0> {
public:
enum { result = 1};
};
enum test { one, max = 4294967295 };
enum test_2 { last = 4294967295*2 };
int main() {
std::cout << "pow<2>: \t" << pow<2>::result << std::endl;
std::cout << "pow<4>: \t" << pow<4>::result << std::endl;
std::cout << "pow<30>: \t" << pow<30>::result << std::endl;
std::cout << "pow<31>: \t" << pow<31>::result << std::endl;
std::cout << "max test: \t" <<
std::numeric_limits<std::underlying_type<test>::type>::max() << std::endl;
std::cout << "max test_2: \t" <<
std::numeric_limits<std::underlying_type<test_2>::type>::max() << std::endl;
return 0;
}
编译输出:
test.cpp:7:19: warning: integer overflow in expression [-Woverflow]
enum { result = 2*pow<i-1>::result};
^
test.cpp:7:7: warning: overflow in constant expression [-fpermissive]
enum { result = 2*pow<i-1>::result};
程序输出:
pow<2>: 4
pow<4>: 16
pow<30>: 1073741824
pow<31>: -2147483648
max test: 4294967295
max test_2: 18446744073709551615
为什么 class pow 中的枚举范围较小?据我了解,对于每个 'i' 值,我都有一个不同的 class 实例化,因此它有一个单独的枚举类型。因此,对于 'i' > 31,枚举应该是 64 位的,就像 test_2 一样。我哪里错了?
我试了 gcc 4.8 和 gcc 5.4 结果是一样的。
Unscoped enumeration
enum name { enumerator = constexpr , enumerator = constexpr , ... }
(1)
(...)
1) Declares an unscoped enumeration type whose underlying type is not fixed (in this case, the underlying type is either int or, if not all enumerator values can be represented as int, an implementation-defined larger integral type that can represent all enumerator values. If the enumerator-list is empty, the underlying type is as if the enumeration had a single enumerator with value 0).
所以在模板一中,您的编译器似乎选择了 int,最大值为 +-2147483648(31 位 + 1 表示符号)。在 test
中,编译器似乎认识到这是不够的,并选择 unsigned int
最大值为 4294967296(32 位)。在 test _2
中,编译器认识到这也是不够的,并选择了 64 位的无符号类型(最大 18446744073709551616)。
将您的枚举声明为
enum { result = 2*pow<i-1>::result, randomMax = \*insert anything large here*\};
应该可以解决问题。第二个值只需要强制编译器选择一个足够长的类型来保存你需要的所有值。
深入研究模板元编程,我发现了 C++ 中枚举范围的奇怪行为。我收到 警告:表达式 中的整数溢出,看起来我实际上不想要超出枚举范围的值。这是代码:
#include <iostream>
#include <limits>
template <int i>
class pow {
public:
enum { result = 2*pow<i-1>::result};
};
template<>
class pow<0> {
public:
enum { result = 1};
};
enum test { one, max = 4294967295 };
enum test_2 { last = 4294967295*2 };
int main() {
std::cout << "pow<2>: \t" << pow<2>::result << std::endl;
std::cout << "pow<4>: \t" << pow<4>::result << std::endl;
std::cout << "pow<30>: \t" << pow<30>::result << std::endl;
std::cout << "pow<31>: \t" << pow<31>::result << std::endl;
std::cout << "max test: \t" <<
std::numeric_limits<std::underlying_type<test>::type>::max() << std::endl;
std::cout << "max test_2: \t" <<
std::numeric_limits<std::underlying_type<test_2>::type>::max() << std::endl;
return 0;
}
编译输出:
test.cpp:7:19: warning: integer overflow in expression [-Woverflow]
enum { result = 2*pow<i-1>::result};
^
test.cpp:7:7: warning: overflow in constant expression [-fpermissive]
enum { result = 2*pow<i-1>::result};
程序输出:
pow<2>: 4
pow<4>: 16
pow<30>: 1073741824
pow<31>: -2147483648
max test: 4294967295
max test_2: 18446744073709551615
为什么 class pow 中的枚举范围较小?据我了解,对于每个 'i' 值,我都有一个不同的 class 实例化,因此它有一个单独的枚举类型。因此,对于 'i' > 31,枚举应该是 64 位的,就像 test_2 一样。我哪里错了?
我试了 gcc 4.8 和 gcc 5.4 结果是一样的。
Unscoped enumeration
enum name { enumerator = constexpr , enumerator = constexpr , ... }
(1)
(...)
1) Declares an unscoped enumeration type whose underlying type is not fixed (in this case, the underlying type is either int or, if not all enumerator values can be represented as int, an implementation-defined larger integral type that can represent all enumerator values. If the enumerator-list is empty, the underlying type is as if the enumeration had a single enumerator with value 0).
所以在模板一中,您的编译器似乎选择了 int,最大值为 +-2147483648(31 位 + 1 表示符号)。在 test
中,编译器似乎认识到这是不够的,并选择 unsigned int
最大值为 4294967296(32 位)。在 test _2
中,编译器认识到这也是不够的,并选择了 64 位的无符号类型(最大 18446744073709551616)。
将您的枚举声明为
enum { result = 2*pow<i-1>::result, randomMax = \*insert anything large here*\};
应该可以解决问题。第二个值只需要强制编译器选择一个足够长的类型来保存你需要的所有值。