2013-08-16 16 views
11

Matthieuの答えhereを読んだ後、私はこれを自分で試してみることにしました。SFINAE declatypeカンマ演算子

SFINAEがT::fooにアクセスしようとしている関数has_fooを起動せずに呼び出されないため、コンパイルが失敗します。

error: ‘struct Bar’ has no member named ‘foo’ 

私は何かを見逃しているのですか、この方法ではできないことを試みていますか?

全examplar下記(Iは、GCC-4.7.2を使用しています):

#include <iostream> 

// culled by SFINAE if foo does not exist 
template<typename T> 
constexpr auto has_foo(T& t) -> decltype((void)t.foo, bool()) 
{ 
    return true; 
} 
// catch-all fallback for items with no foo 
constexpr bool has_foo(...) 
{ 
    return false; 
} 
//----------------------------------------------------- 

template<typename T, bool> 
struct GetFoo 
{ 
    static int value(T& t) 
    { 
     return t.foo; 
    } 
}; 
template<typename T> 
struct GetFoo<T, false> 
{ 
    static int value(T&) 
    { 
     return 0; 
    } 
}; 
//----------------------------------------------------- 

template<typename T> 
int get_foo(T& t) 
{ 
    return GetFoo<T, has_foo(t)>::value(t); 
} 
//----------------------------------------------------- 

struct Bar 
{ 
    int val; 
}; 

int main() 
{ 
    Bar b { 5 }; 
    std::cout << get_foo(b) << std::endl; 
    return 0; 
} 
+0

これは 'foo'ではなく、' val'男です! – Rapptz

+0

@Rapptz - 正確に! ** has_foo(true)メソッドを外し**フォールバックメソッドを使用することになっています。 –

+0

ああ、ごめんなさい。 – Rapptz

答えて

10

ここで主な問題AFAICSあなたはconstexprとして実行時参照を使用していることです関数のパラメータです。これを置き換えるだけで正常に動作します。

#include <iostream> 

// culled by SFINAE if foo does not exist 
template<typename T> 
constexpr auto has_foo(int) -> decltype(std::declval<T>().foo, bool()) 
{ 
    return true; 
} 
// catch-all fallback for items with no foo 
template<typename T> constexpr bool has_foo(...) 
{ 
    return false; 
} 
//----------------------------------------------------- 

template<typename T, bool> 
struct GetFoo 
{ 
    static int value(T& t) 
    { 
     return t.foo; 
    } 
}; 
template<typename T> 
struct GetFoo<T, false> 
{ 
    static int value(T&) 
    { 
     return 0; 
    } 
}; 
//----------------------------------------------------- 

template<typename T> 
int get_foo(T& t) 
{ 
    return GetFoo<T, has_foo<T>(0)>::value(t); 
} 
//----------------------------------------------------- 

struct Bar 
{ 
    int val; 
}; 
struct Foo { 
    int foo; 
}; 

int main() 
{ 
    Bar b { 5 }; 
    Foo f { 5 }; 
    std::cout << get_foo(b) << std::endl; 
    std::cout << get_foo(f) << std::endl; 
    return 0; 
} 
+0

もし可能であればフォローアップしてください。あなたは 'int'パラメータ(そしてこの型の値を渡します)を使用して、catch allとcatchを区別します。 'foo'または' bar'メンバーの値を(その順番に)取るという要件があるとしましょう。この方法はこのタスクに適していますか、他のルートをとるべきですか? –

+0

@RedXIII:はい、この方法が適しています。キャッチオールの場合、単に '.bar'を使用してください。 '.foo'がある場合、最初のメソッドが使用されます。 '.foo'がなくても' .bar'があれば、catch-allが選択されてコンパイルされます。どちらもない場合は、キャッチオールが選択され、コンパイルされません。 – MSalters

+1

@RedXIII:はい、 'int'と' long'( 'int''''''''''''''')を使って複数に拡張できますが、これをカスタマイズすることもできます基本クラスを使用して任意の優先順位に設定します。 – Puppy