2016-07-03 3 views
4

템플릿 메타 프로그래밍을 파고 C++에서 enum의 범위와 함께 이상한 동작을 발견했습니다. 나는 경고를받습니다 : 표현식이 인 정수 오버플로입니다. 실제로 열거 형 범위를 벗어나는 값을 원하지 않는 것처럼 보입니다.템플릿 클래스에있을 때 enum에 정수 오버플로가 발생했습니다.

#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 

이 클래스 펑의 열거가 작은 범위를 가지고 왜? 내가 아는 한, 모든 'i'값에 대해 인스턴스화 된 다른 클래스가 있으므로 별도의 enum 형식이 있습니다. 결과적으로 'i'> 31의 경우 enum은 test_2와 같이 64 비트 여야합니다. 내가 틀린 곳?
나는 gcc 4.8과 gcc 5.4를 시도했고 그 결과는 같다.

+0

C++ 11을 사용하는 경우'enum' 대신'static constexpr' 변수를 사용하거나 다음과 같이 열거 형을 지정할 수 있습니다 :'enum : long int {...};' – Nelfeal

답변

0

cppreference.com

범위가 지정되지 않은 열거
enum name { enumerator = constexpr , enumerator = constexpr , ... } (1)
(...)
1)이 경우, 그 내부 형식 고정되지 않는 범위가 지정되지 않은 열거 타입 (선언은 내부 유형이 이거나 int가 아닌 경우 모든 열거 자 값을 int로 표시 할 수 있습니다. 모든 열거 자 값을 나타낼 수있는 구현 정의의 더 큰 정수 유형입니다. 열거 자 목록이 비어 있으면 th e 기본 유형은 열거 형에 값이 0 인 단일 열거 자 (enumerator)가있는 것과 같습니다.

그래서 하나의 컴파일러에서 + -2147483648 (부호의 경우 31 비트 + 1)의 최대 값을 사용하여 int를 선택하는 것으로 보입니다. test에서 컴파일러는 이것이 충분하지 않다고 인식하여 최대 값이 4294967296 (32 비트) 인 unsigned int을 선택합니다. test _2에서 컴파일러는 이것을 인식하지 못하고 64 비트 (최대 18446744073709551616)의 부호없는 유형을 선택합니다.

트릭을 할해야

enum { result = 2*pow<i-1>::result, randomMax = \*insert anything large here*\}; 

로 열거 선언. 두 번째 값은 컴파일러가 필요한 모든 값을 포함 할 수있을만큼 긴 형식을 선택하도록 강제합니다.

+0

thanks , 답을 완성하십시오 : –

+1

첫 번째 : 많은 수의 경우'template '이 더 좋습니다. 두 번째 :'result = pow :: result * 2'에서 타입에 대해 생각해보십시오. _pow <0> :: result_는 int이며, 2를 곱한 값이 int이므로 pow <1> :: result가 int이며 그 패턴이 반복됩니다. 그런 식으로 재귀에서 유형을 변경할 수있는 방법이 없습니다 (왜냐하면 enum은 구체적인 유형을 가지고 있기 때문에 인식하지 못했습니다). 곱셈이 긴 타입을 제공하고 컴파일러가 _result_에 사용할 타입을 결정하기 때문에'enum {result = 2l * pow :: result}'이면 충분하다. –

관련 문제