2016-10-30 8 views
3

私はSFINAEの周りを頭で囲んでいます。 クラスに「乗客」というメソッドがあるかどうかを確認するために使用しています。SFINAE C++メソッドチェック

いくつかのオンラインの例では、次のテンプレートクラスを構築しました。

#ifndef TYPECHECK 
#define TYPECHECK 

#include "../Engine/carriage.h" 

namespace TSS{ 

template<typename T> 
class has_passengers{ 
private: 
    typedef char one; 
    typedef struct{char a[2];} two; 

    template<typename C> static one test(decltype(&C::Passengers)); 
    template<typename C> static two test(...); 
public: 
    static bool const value = sizeof(test<T>(0)) == sizeof(one); 
}; 

template<typename T> 
struct CarriageTypeCheck{ 
    static_assert(has_passengers<T>::value, "Train initialized with illegal carriage"); 
}; 

} 


#endif // TYPECHECK 

私は2つのテストの方法のいずれかが選択されているかの部分を得るが、test<T>は次の行に0に初期化され、なぜ私が理解していないことである。

static bool const value = sizeof(test<T>(0)) == sizeof(one); 

私ができますチェックが機能するために0がどのように重要であるかは分かりません。 別のもの - なぜdecltypeが使用されていますか?

+0

クラスにメンバー関数「乗客」があるかどうかはチェックしていません。あなたは機能しているかもしれないメンバーである乗客がいるかどうかをチェックしていますが、そうである必要はありません。 – krzaq

+0

良い点!ありがとう! –

答えて

2

第1のオーバーロードされた関数(潜在的に)は、クラスメソッドへのポインタをパラメータとしてとります。 C++のCの遺産のために、値0はNULLポインタに変換可能です。つまり、nullptrです。したがって、SFINAEが最初のオーバーロードされた関数を取り除かない場合、test<T>(0)は有効な関数呼び出しになり、sizeofsizeof(one)に等しくなります。それ以外の場合は、2回目のオーバーロードされた関数呼び出しに解決されます。

なぜdecltypeが使用されているかについての短い答え。それ以外の場合は、C++が有効ではありません。関数宣言では、関数のパラメータは型でなければならず、関数へのパラメータの型を指定する必要があります。 &C::Passengersは(意図された用途の文脈で)タイプではないので、これはC++には有効ではありません。 decltype()はその引数の型を自動的に取得し、それを有効なC++にします。

+0

。しかし、Tに乗客がいない場合、それは 'sizeof(2)'と等しくないでしょうか?その後、呼び出しはtest(nullpointer)になり、サイズは2になります。 –

+0

@BenjaminLarsen Tに乗客がいない場合、型控除は失敗し、関数テンプレートは無視されます。それがSFINAEの仕組みです。 SFINAEがなければ、このケースではnullポインタを渡すような規則はありません。コンパイルエラーが発生します。 – songyuanyao

+0

私は今それを得たと思う!君たちありがとう。 –

1

チェックが機能するためには、どのように0が重要かわかりません。

0は両方のケース(つまり、オーバーロードされた2つのオーバーロードtest)の引数として使用できます。メンバーポインタ(ヌルポインタとして扱われる)と可変引数の場合...

もう1つの理由 - なぜdecltypeが使用されていますか?

decltypetestのパラメータとしてメンバポインタ(すなわち&C::Passengers)のタイプを記述するために使用されます。