2012-08-08 24 views
5

decltypeの結果をC++ 11で比較する方法はありますか?decltypeの比較

つまり

は、なぜこのコードは無効です:

template<typename T, typename U> 
void func(T& t, U& u) { 
    if(decltype(t) == decltype(u)) { 
     // Some optimised version for this case 
    } else { 
     // A more general case for differing types 
    } 
} 

私はいくつかのケースでは、この特定の問題は、テンプレートの部分特殊化によって解決することができることを知っています。私の質問はdecltypeの比較です。

編集: SFINAEを介してフリー機能のデフォルトを提供しようとする過程で質問が出てきました。これが無効である理由を、より良い質問がされているだろうおそらく:

template<bool B> 
bool SomeFunction() { ... } 

template<typename T, typename U> 
bool SomeFunctionWrapper(T& t, U& u) { 
    SomeFunction<decltype(t) == decltype(u)>(); 
} 

私は以来、別の解決策を見つけた(つまり、すべてのテンプレートを含まない)が、1つの段階で、私はこの試みた:

// If it exists, the free function is defined as 
// bool AFreeFunction(); 
typedef struct { char } undefined; 
template<typename T = void> 
undefined AFreeFunction(); 

template<bool B> 
bool AFreeFunctionWrapper_() { 
    return false; 
} 

template<> 
bool AFreeFunctionWrapper_<false>() { 
    return AFreeFunction(); 
} 

bool AFreeFunctionWrapper() { 
    return AFreeFunctionWrapper_<decltype(AFreeFunction()) == decltype(undefined)>(); 
} 

私は最終的にGCC 4.6で動作するこの戦略の変種を得ましたが、2012 RCであっても、デフォルトのテンプレート引数はMSVCのテンプレート関数には使用できません。したがって、最終的な解は次のようになります。

class AFreeFunction { 
public: 
    operator bool() { return false; } 
}; 

関数が定義されていれば、呼び出されます。そうでない場合は、そのクラスのコンストラクタとして解釈され、暗黙的にboolにキャストされます。

+0

上記のフリー関数形式は、部分的な特殊化では解決できないことに注意してください。それを可能にするためにクラステンプレートとして再定式化する必要があります。 – Tom

+0

いいえ、クラステンプレートである必要はありません。*オーバーロードされた*関数テンプレートの単純なセットにすることができます。 –

+0

@ n.m。いい視点ね。 – Tom

答えて

8

通常、この問題はタグのディスパッチによって解決します。また、すでに「宣言された型」がtu-T&およびU&になっています。等価の型を比較す​​るには、std::is_sameを使用します。しかし、オーバーロードの解決は、すでにあなたのため、この問題を解決:fに、両方の引数が同じ型である場合

template<class T> 
void f(T& v1, T& v2){ ... } // #1 

template<class T, class U> 
void f(T& t, U& u){ ... } // #2 

#1は#2よりも特化しています。あなたは、どんな理由であれ、手動式の比較です介してこれを解決することを主張した場合、ここでは前述のポイントを適用するどのように見えるかです:

#include <type_traits> 

namespace detail{ 
template<class T, class U> 
void f(T& t, U& u, std::true_type){ ... } // #1 

template<class T, class U> 
void f(T& t, U& u, std::false_type){ ... } // #2 
} // detail:: 

template<class T, class U> 
void f(T& t, U& u){ 
    detail::f(t, u, std::is_same<T,U>()); // tag dispatching 
} 

std::is_sameは、両方のタイプが同じであればstd::true_typeから派生し、std::false_typeから場合しますない。

+0

コンパイラは、作成された真偽型を常に排除しますか?私は 'bool'でテンプレートを特化し、代わりに型を渡しました。そうすれば、無駄なタイプが作成されることはありません。 – KitsuneYMG

+0

私はこれを得て、それがおそらく答えになると思っていましたが、それについて他のアイデアを集めようとしていました。実際の文脈は、テンプレート bool Function(){{}}と 'template <> bool Function (){...}'を作成しようとしていて、 'bool b = Function (); '。私はこの詳細を質問に加えるかもしれない。 – Tom

4

なぜ無効ですか? decltypeの結果は、よくタイプです。だから、それは明らかに言語が許さないようなものを言っています。

if (int == int) 

関数の2つの部分を分けて、特殊な部分を特殊なクラスの関数の中に入れ、そこに呼び出しを転送する必要があります。それは痛い。

または実装で正しく実装されている場合は、実行時の型情報typeidを使用することもできますが、プログラムの実行時にすべてを延期します(これにより、最適化はより少なくなります)。

+0

おそらく私は質問をあまり単純化しました。私は 'if(int == int)'が無効であることを知ります。 'some_template 'がなぜ無効であるのかは私には分かりません。 'some_template 'の類推を考えてみましょう。 'decltype'は' sizeof'の自然な拡張であると考えられます。 – Tom

+0

@Tom: 'sizeof'は* value *を返します。 'decltype'は" a * type * "を返します。彼らは別の獣です。 – Mehrdad

+1

本当にそうではありません。 'sizeof'はコンパイラがコンパイル時にテンプレートのインスタンス化を解決することを可能にする_constant_値を返します。私の質問は、標準委員会がタイプのコンパイル時の比較を可能にするため、コンパイル時の型の比較を許可しなかった理由です。 – Tom

3

あなたはこのSFINAE(std::enable_if)を使用して行うことができます。Mehrdadが言うようdecltype(t)decltype(u)は種類(T &それぞれU &)、値ではありませんので、値式のレベルで比較することはできません、

template<typename T, typename U> 
typename std::enable_if<std::is_same<T, U>::value, void>::type func(T& t, U& u) { 
    std::cout << "same\n"; 
} 
template<typename T, typename U> 
typename std::enable_if<!std::is_same<T, U>::value, void>::type func(T& t, U& u) { 
    std::cout << "different\n"; 
} 

をが、メタ表現(テンプレート)レベルで比較されなければならない。

+0

私はそれがどのように動作するのか分かります。標準委員会が 'decltype'の結果を比較することができない理由があるのか​​どうか疑問に思っています。私が達成しようとしていたことの編集された質問を参照してください。実際には、テンプレート引数のコンテキストで比較が行われていて、あなたの提案にかなり近いです。私は本当に 'std :: enable_if'を認識しておらず、' std :: is_same'について聞いていませんでした。 – Tom

+0

@Tom 'decltype'は関数ではなく、演算子なので、その" result "は値のように振る舞う必要はありません。 – ecatmur

+0

私はその推論に従うか分からない。結局、他のすべての演算子の結果は値のように振る舞います。 'sizeof'は非常に密接に関連する演算子で、値のように振る舞いますが、' decltype'と同じようにコンパイル時に他の(定数)値と比較できます。 – Tom