2012-06-09 2 views
6

編集:は私の質問への短い答えは、私がSFINAEは何ができるかの誤表示を持っていたし、それがすべてで関数本体をチェックしないということである。does sfinae instantiates a function body?関数が存在し、コンパイル時に使用できるかどうかを検出する方法はありますか?

私はこれと同じ問題を持っている:Is it possible to write a template to check for a function's existence?

違いは、機能が存在するかどうかだけでなく、SFINAEを実際に通過するかどうかを知りたいということです。ここで私が達成しようとしているものの例である:

struct A 
{ 
    void FuncA() { std::cout << "A::FuncA" << std::endl; } 
}; 

struct B 
{ 
    void FuncA() { std::cout << "B::FuncA" << std::endl; } 
    void FuncB() { std::cout << "B::FuncB" << std::endl; } 
}; 

template<typename T> 
struct Inter 
{ 
    void FuncA() { t.FuncA(); } 
    void FuncB() { t.FuncB(); } 

    T t; 
}; 

// Always takes some sort of Inter<T>. 
template<typename InterType> 
struct Final 
{ 
    void CallFuncs() 
    { 
     // if(t.FuncA() exists and can be called) 
      t.FuncA(); 

     // if(t.FuncB() exists and can be called) 
      t.FuncB(); 
    } 

    InterType t; 
}; 

void DoEverything() 
{ 
    Final<Inter<A>> finalA; 
    Final<Inter<B>> finalB; 

    finalA.CallFuncs(); 
    finalB.CallFuncs(); 
} 

注意(CallFuncsであること)、FUNCA()とfuncBの()の両方が常に存在しますが、彼らはTが使用するタイプに応じて、コンパイルできませんインターの上記のリンクされた質問で答えを使用しようとしたとき、関数が存在するかどうかをチェックするだけなので、実際にコンパイルすることはできません私ができるどのような方法があるかどう

template<typename InterType> 
typename std::enable_if< ! /* how to determine if FuncA can be called? */>::type TryCallFuncA(InterType& i) 
{ 
} 
template<typename InterType> 
typename std::enable_if</* how to determine if FuncA can be called? */>::type TryCallFuncA(InterType& i) 
{ 
    i.FuncA(); 
} 

template<typename InterType> 
typename std::enable_if< ! /* how to determine if FuncB can be called? */>::type TryCallFuncB(InterType& i) 
{ 
} 
template<typename InterType> 
typename std::enable_if</* how to determine if FuncB can be called? */>::type TryCallFuncB(InterType& i) 
{ 
    i.FuncB(); 
} 

template<typename InterType> 
struct Final 
{ 
    void CallFuncs() 
    { 
     TryCallFuncA(t); 
     TryCallFuncB(t); 
    } 

    InterType t; 
}; 

が、私はよく分からない。私は条件付きで、私は私のようなenable_if使用することができます理解の関数を呼び出すために

)...アップ何かをネジなかったですenable_ifに渡すブール値を取得します。私はこれを達成する方法がありますか、あるいは機能が存在するかどうかを示す手作業で維持されている何らかの種類の特性に戻す必要がありますか?私の実際の状況では、クラスの実装を重要なメモを追加するには:それは、私が

編集をMSVC 2010を使用している利用可能なC++ 11の機能セット限り価値がある何のため

Inter :: FuncA/FuncBがコンパイルされるかどうかを判断する必要がある時点で、Interは効果的に不透明であるため、子タイプをバブルアップして関数の存在を確認することはできません。

答えて

8

私は今、これを確認する時間がありませんが、あなたはFinalの専門追加することができます。template <typename T> struct Final< Inner<T> >;(また、タイプは常にInnerであることを確実にするのに役立つものを使用すると、Interをインスタンス化するために使用されるタイプを抽出することができます。。

今、第二の問題は、(これがジェネリックにする必要がない場合)私は、これは複雑すぎてはならないと考えているメンバ関数が存在するかどうかを検出するために、SFINAEを使用する方法である:

// Find out whether U has `void f()` member 
template <typename U> 
struct has_member_f { 
    typedef char yes; 
    struct no { char _[2]; }; 
    template<typename T, void (T::*)() = &T::f> 
    static yes impl(T*); 
    static no impl(...); 

    enum { value = sizeof(impl(static_cast<U*>(0))) == sizeof(yes) }; 
}; 

これをもう少し拡張して、それを少し増やすことができるかもしれませんネリカルですが、機能の名前はあなたがジェネリックにすることはできないと思います。もちろん、has_member_##argを生成し、&T:: argを使用するマクロとして書くことができます。メンバーのタイプはおそらく一般化する方が簡単かもしれません...

また、私はこれが一般的なものになるとは思わないので、has_memberの中で直接あなたのタイプのトリックを使うことができます:callFuncA 2つのテンプレート任意の2番目の引数に必要なシグニチャを指定し、デフォルトで&T::FuncAにコールを転送し、もう1つは省略記号で省略記号を使用します。 callFuncscallFuncAcallFuncBとなり、SFINAEはフォワーダまたは正午のいずれかにディスパッチし、目的の動作を得ます。

template<typename T> 
struct Final< Inter<T> > 
{ 
    template <typename U, void (U::*)() = &U::FuncA> 
    void callFuncA(Inter<T>* x) { 
     x.FuncA(); 
    } 
    void callFuncA(...) {} 

    void CallFuncs() { 
     callFuncA(&t);     // Cannot pass nonPOD types through ... 
     // Similarly TryCallFuncB(t); 
    } 
    Inter<T> t; 
}; 
+0

私が正しく覚えていれば、この解決策をC++ 11でのみ利用できるようにするC++ 03のデフォルト引数と関数テンプレートに問題があります。あなたは確認してもらえますか? –

+0

@MatthieuM .:これはC++ 11の解決策です。 C++では、関数テンプレートにデフォルト引数を指定することはできません。これは、新しい標準のレーダーの下で飛んできた本当に素晴らしい機能であり、Xが真でなければ*特定の機能*が過負荷解決に参加しないことを標準が要求している多くの場合に必要です*(つまり、SFINAEは必須です)。 –

+0

残念ながら、それはVS(2010年または2012年)ではサポートされていません。解決策を理解するために、デフォルトの引数&U :: FuncAは存在することだけがチェックされているだけでなく、コンパイルされていると正しくコンパイルされます(例えば、Inter に与えられた型自体がテンプレートクラス例えばstruct A )、FuncA/FuncBの実装はそのタイプに依存します)。 – Screndib

関連する問題