2013-06-15 12 views
10

1週間前に、クラステンプレートが特定のメンバー関数を持っていた場合にのみ、クラステンプレートをどのようにインスタンス化できるかを質問しました。私の答えでは、私は複雑な解決策の一種を持っています。しかし、私は自分でそれをやろうとしました。私はちょうど与えられたタイプTを把握するのに十分なものが0のパラメータを取るfという名前のvoid関数を持っているかどうかを知りたいと思っていました。これはSFINAEとは考えられますか?

#include <type_traits> 
#include <utility> 

template <typename T, typename = void> 
struct has_f : std::false_type { }; 

template <typename T> 
struct has_f< 
    T, 
    decltype(std::declval<T>().f(), void())> : std::true_type { }; 

template <typename T, typename = typename std::enable_if<has_f<T>::value>::type> 
struct A { }; 

struct B 
{ 
    void f(); 
}; 

struct C { }; 

template class A<B>; // compiles 
template class A<C>; // error: no type named ‘type’ 
        // in ‘struct std::enable_if<false, void>’ 

もしそうなら、なぜ他の回答がthis thread?

+2

を使用するには。なぜ他の答えがより複雑になっているのかは分かりません。 –

+0

'has_f'自体がSFINAEに依存していることを明確にするため、' A'はそうではありません。 –

+0

可能性として、SFINAEはいくつかのコンパイラ(* cough * MSVC2012)のサックをサポートしているので、その複雑さのいくつかは、より移植性の高いSFINAEを持つための回避策かもしれません。 'std :: declval ()'?)()のように、 'std :: declval ().f()'と 'std :: declval () 'this'機能へのrvalue参照のため、C++ 1yではさまざまなことがあります。 – Yakk

答えて

7

うんでとても複雑で、あなたはC++ 11 SFINAEの最も簡単な、最も慣用なスタイルでそれを解決しました。

戻り値の型がvoidであること、非静的メンバーであること、パラメータがないことを確認していないことに注意してください。 fは引数なしで単純に呼び出し可能です。それはファンクターでもあります。

voidを返す引数なしのメンバーの非静的機能をチェックはい、これはSFINAEで、はい、これは正しいです

template <typename T> 
struct has_f<T, decltype(void(static_cast< void (T::*)(void) >(&T::f))) > 
    : std::true_type {}; 

template <typename T> 
struct has_f<T, decltype(void(static_cast< void (T::*)(void) const >(&T::f))) > 
    : std::true_type {}; 
+0

私は 'std :: result_of'を使って戻り値の型がvoidかどうかを調べます。 –

+0

@MemyselfandIそれは一つの方法です、あなたは 'decltype'を使うこともできます。 'std :: result_of'は、' std :: bind'と 'std :: function'で使用されるINVOKEコンセプトをサポートするために、ちょっとした奇妙なダンスを行います。一度にいくつかの条件を確認するための簡単な方法については、私の編集を参照してください。いずれにしても、 'std :: is_same'が必要です。 – Potatoswatter

+0

私はあなたが 'std :: is_same :: value'(閉じたカッコ)を意味すると思っています。 – hvd

関連する問題