2011-01-26 7 views
6

SFINAEを使用して、指定されたクラスに対して空き関数がオーバーロードされているかどうかを検出する方法はありますか?SFINAE:クラスに空き関数があるかどうかを検出

基本的に、私は以下のソリューションを持っている:

struct has_no_f { }; 

struct has_f { }; 

void f(has_f const& x) { } 

template <typename T> 
enable_if<has_function<T, f>::value, int>::type call(T const&) { 
    std::cout << "has f" << std::endl; 
} 

template <typename T> 
disable_if<has_function<T, f>::value, int>::type call(T const&) { 
    std::cout << "has no f" << std::endl; 
} 

int main() { 
    call(has_no_f()); // "has no f" 
    call(has_f()); // "has f" 
} 

単にそこfoobarタイプの多くは、実際にあるとcall機能は、それらの知識を持たないため、基本的には(動作しませんcallをオーバーロードcallは内部にあり、ユーザは自分のタイプを提供します)。

私はC++ 0xを使うことができません。すべての現代的なコンパイラのための解決策が必要です。

注:残念ながらここではsimilar questionへの解決策はありません。

+0

非常に不都合な問題です。私は解決策も知りたい。 –

+0

インスタンシエーションの時点でしか表示されない機能を検出しますか? –

+0

@Johannes私の場合は本当に問題ではありません。 (関数テンプレートの)インスタンシエーションの時点で、すべての候補関数*がわかります。 –

答えて

3
#include <iostream> 
#include <vector> 
#include <algorithm> 
#include <utility> 
#include <functional> 
#include <type_traits> 

struct X {}; 
struct Y {}; 

__int8 f(X x) { return 0; } 
__int16 f(...) { return 0; } 

template <typename T> typename std::enable_if<sizeof(f(T())) == sizeof(__int8), int>::type call(T const& t) { 
    std::cout << "In call with f available"; 
    f(t); 
    return 0; 
} 

template <typename T> typename std::enable_if<sizeof(f(T())) == sizeof(__int16), int>::type call(T const& t) { 
    std::cout << "In call without f available"; 
    return 0; 
} 

int main() { 
    Y y; X x; 
    call(y); 
    call(x); 
} 

f()の戻り値の型をすばやく変更すると、従来のSFINAEソリューションが得られます。 boostが許可されている場合

+0

私はfの過負荷が検出されるべきだと考えています。解決策の一部ではありません。 – aschepler

3

、次のコードは、あなたの目的を満たすことがあります

#include <boost/type_traits.hpp> 
#include <boost/utility/enable_if.hpp> 
using namespace boost; 

// user code 
struct A {}; 
static void f(A const&) {} 
struct B {}; 


// code for has_f 
static void f(...); // this function has to be a free standing one 

template< class T > 
struct has_f { 
    template< class U > 
    static char deduce(U(&)(T const&)); 

    template< class U, class V > 
    static typename disable_if_c< is_same< V, T >::value, char(&)[2] >::type 
    deduce(U(&)(V const&)); 

    static char (&deduce(...))[2]; 

    static bool const value = (1 == sizeof deduce(f)); 
}; 

int main() 
{ 
    cout<< has_f<A>::value <<endl; 
    cout<< has_f<B>::value <<endl; 
} 

しかし、厳しい制限があります。
このコードでは、すべてのユーザー関数に(T const&)、 という署名があると仮定しているので、(T)は使用できません。
上記の機能void f(...)は、フリースタンディングである必要があるようです。
コンパイラが2つの位相ルックアップを通常どおりに実行する場合、おそらく has_fクラス テンプレートの定義の前にすべてのユーザー関数を表示する必要があります。
正直なところ、私はコードの有用性を確信していませんが、とにかく私は これが役立つことを願っています。

関連する問題