2011-01-21 4 views
18

整数型の "signed-ness"に基づく部分テンプレートの特殊化?与えられた

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

unsignedタイプで使用する場合には、警告を生成します。

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

Tunsignedタイプの場合に比較n >= 0を行うにはない任意の巧妙な方法はありますか?私は部分的なテンプレートの専門化を追加しようとしました: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++ 0xのか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符号なしフラグ

:次はあなたがunsignedタイプ等の特殊なテンプレート関数の実装を実装することができますあまりにも

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

最後のトリック+1 +1 – TonyK

0

GCCをだまして表示されます使用したい符号なしタイプの場合は、フラグを追加してください:

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で実装できる唯一のソリューションでもあるようです。それは私の本の明確なプラスです。 私はそれが働くようにアップアップします;) – 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…

関連する問題