2011-01-21 5 views
18

을 감안할 때 :정수형의 "signed-ness"에 기반한 부분 템플릿 전문화?

unsigned n; 
f(n); // warning: comparison n >= 0 is always true 

비교 Tunsigned 유형입니다 n >= 0을 할 수없는 어떤 영리한 방법이 있나요 : unsigned 유형을 사용

template<typename T> 
inline bool f(T n) { 
    return n >= 0 && n <= 100; 
} 

경고를 생성? 나는 부분 템플릿 특수화를 추가하는 시도 :

template<typename T> 
inline bool f(unsigned T n) { 
    return n <= 100; 
} 

하지만 GCC 4.2.1 그렇게 좋아하지 않는다. (나는 어쨌든 종류의 부분 템플릿 전문화가 합법적이라고 생각하지 않았습니다.)

+2

참고를 참조하십시오. 즉, 특수화 된 기능, 과부하가 발생하는 기능 및 과부하 해결 방법을 사용하여 무엇을 사용할지 결정하는 규칙이 복잡하고 복잡하기 때문에 전체 전문화는 일반적으로 함수 템플릿에 나쁜 개념입니다. 고맙게도 과부하 및 SFINAE (대체 오류는 오류가 아님)로 충분합니다. –

+0

이것에 대해 Clang 3.8 (또는 GCC 8.0)으로부터 경고를받지 못했습니다. 'f'에서 템플릿을 지우면 얻을 수 있습니다. 템플릿 인스턴스화를 고려한'-Wtautological-compare' 버전이 있습니까? – user2023370

답변

22

당신은 is_unsigned 유형의 특성과 enable_if를 사용할 수 있습니다

template <typename T> 
typename std::enable_if<std::is_unsigned<T>::value, bool>::type f(T n) 
{ 
    return n <= 100; 
} 

template <typename T> 
typename std::enable_if<!std::is_unsigned<T>::value, bool>::type f(T n) 
{ 
    return n >= 0 && n <= 100; 
} 

컴파일러는 각각 C + +0을 지원 또는 TR1 경우가 std 또는 std::tr1 네임 스페이스 enable_ifis_unsigned을 찾을 수 있습니다. 그렇지 않으면 Boost에는 형질 라이브러리 유형 인 Boost.TypeTraits이 구현되어 있습니다. enable_if의 부스트 구현은 조금 다릅니다. boost::enable_if_c은 TR1 및 C++ 0x enable_if과 유사합니다.

14

부호없는 정수의 랩 어라운드 동작을 활용할 수 있습니다.

template<bool> struct bool_ { }; 

template<typename T> 
inline bool f(T n, bool_<false>) { 
    return n >= 0 && n <= 100; 
} 

template<typename T> 
inline bool f(T n, bool_<true>) { 
    return n <= 100; 
} 

template<typename T> 
inline bool f(T n) { 
    return f(n, bool_<(static_cast<T>(-1) > 0)>()); 
} 

그것은, >= 0 말을 다시 경고를 피하지 않는 것이 중요합니다.

template<class T> bool f(T val); 
template<> bool f<unsigned>(unsigned val); 

UPDATE 서명되지 않은 플래그

당신은 모든 다른 구현을 구현할 수 있습니다 다음은 너무

template<typename T> 
inline bool f(T n) { 
    return (n == 0 || n > 0) && n <= 100; 
} 
+0

+1 마지막 트릭에 대해 +1 – TonyK

0

당신은 같은 unsigned 유형에 대한 특별한 템플릿 기능 구현을 구현할 수 GCC를 속여 표시 사용하려는 서명되지 않은 유형 또는 다음과 같은

과 같은 bool 플래그를 추가하십시오. 0
template <class T, bool U> bool f(T val) 
{ 
     if (U) 
       return val <= 100; 
     else 
       return (val >=0) && (val <= 100); 
} 

... 

cout << f<int, false>(1) << endl; 
cout << f<int, false>(-1) << endl; 
cout << f<char, true>(10) << endl; 
+0

char, short, int, long과 같은 모든 부호없는 유형에서 작동해야한다는 점을 제외하고는. –

+0

해결책은 "enable_if"(또는 유사한 기능)을 이용하는 다른 방법보다 훨씬 상세합니다. –

+1

당신의 솔루션은 또한 부스트를 사용하지 않고 C++ 03로 구현 될 수있는 유일한 솔루션 인 것처럼 보입니다. 그건 내 책에서 명확한 플러스입니다. 내가 작동하게되면 upvote 할 것이다;) – Paul

1

T가 부호없는 유형인 경우 비교 n> = 0을 수행하지 않는 영리한 방법이 있습니까? 부분 템플릿 전문화를 추가하려고 시도했습니다.

옵티마이 저는 조건을 감지 한 후 비교할 코드를 삭제해야합니다.

Clang의 경우 경고를 스쿼시하려면 -Wno-tautological-compare을 추가하십시오. GCC/G ++의 경우 경고를 스쿼시하려면 -Wno-type-limits을 추가하십시오.

당신은 당신이 할 수있는 pragma diagnostic {push|pop}을 지원하는 컴파일러를 사용하는 경우 :

#if (GCC_VERSION >= 40600) || (LLVM_CLANG_VERSION >= 10700) || (APPLE_CLANG_VERSION >= 20000) 
# define GCC_DIAGNOSTIC_AVAILABLE 1 
#endif  

#if MSC_VERSION 
# pragma warning(push) 
# pragma warning(disable: 4389) 
#endif 

#if GCC_DIAGNOSTIC_AVAILABLE 
# pragma GCC diagnostic push 
# pragma GCC diagnostic ignored "-Wsign-compare" 
# if (LLVM_CLANG_VERSION >= 20800) || (APPLE_CLANG_VERSION >= 30000) 
# pragma GCC diagnostic ignored "-Wtautological-compare" 
# elif (GCC_VERSION >= 40300) 
# pragma GCC diagnostic ignored "-Wtype-limits" 
# endif 
#endif 

template<typename T> 
inline bool f(T n) { 
    return n >= 0 && n <= 100; 
} 

#if GCC_DIAGNOSTIC_AVAILABLE 
# pragma GCC diagnostic pop 
#endif 

#if MSC_VERSION 
# pragma warning(pop) 
#endif 

는 또한 기능 템플릿 만 전체 전문화에 대한 부분 특수화가 없음을 Comparison is always false due to limited range…