2

クラステンプレートがあるとしますtemplate <typename T> class X

タイプTがそのようなメソッドを宣言している場合にのみ、タイプ特性または同様の手法を使用してTの(静的)メソッドを呼び出すことはどういうわけか可能ですか?

template <typename T> 
class X {
    static void foo(){
       if(has_method(T,bar)) //Something like this      
         T::bar(); //If T has no bar() method, then foo does nothing
    }

};
4

2 に答える 2

3
template <typename T>
class X {
public:
    static void foo() {
        foo_impl(static_cast<T*>(nullptr));
    }
private:
    // foo_impl #1
    template <typename U>
    static auto foo_impl(U*) -> decltype(U::bar(), void()) {
        U::bar();
    }

    // foo_impl #2
    static void foo_impl(...) {}
};

SFINAEルールにより、が有効な式でない場合、 foo_impl#1はオーバーロードセットに含まれず、代わりに#2が呼び出されます。型の演繹が#1で成功した場合、省略記号よりも常に優れた変換になります。U::bar()foo_implfoo_impl

Ideoneデモ: http: //ideone.com/UKVmIB

于 2013-02-04T15:31:29.823 に答える
2

まず、コンパイル時に決定を下す必要があります。そうしないと、ブランチにアクセスしたことがない場合でも、関数を提供する必要があります。私は次のようなものを想像することができます:

template <typename T, void (T::*)() > struct HasBar;

template <typename T>
void doBar( HasBar<&T::bar>* ) { T::bar(); }

template <typename T>
void doBar( ... ) {}

template <typename T>
class X
{
    static void f()
    {
        doBar<T>( 0 );
    }
};

それは多かれ少なかれ古典的なトリックです。失敗した場合&T::bar(Tにメンバーバーがないため)、doBar( HasBar<...>)失敗のインスタンス化では、関数はオーバーロードセットに追加されないため、もう1つが呼び出されます。が正当な式である場合&T::bar、両方の関数テンプレートを正常にインスタンス化でき、との0一致の前にポインターへの変換が選択されます...(これは、関数のオーバーロード解決を決定する際の最後の手段です)。

編集:

関数が静的であるという事実を見逃しました。上記は非静的関数の場合です。静的関数の場合、最初の行を次のように変更します。

template <typename T, void (*)() struct HasBar;

残りはそのまま動作するはずです。

于 2013-02-04T15:29:38.807 に答える