2016-05-06 9 views
0

私はSubstitution Fail Is Not An Error(SFINAE)のために夫婦テンプレート化機能を使用しようとしています。そして、私はこのようにそれを行うことができます。これらのテンプレート化された関数は引数を取れないのはなぜですか?

template<typename R, typename S = decltype(declval<R>().test())> static true_type Test(R*); 
template<typename R> static false_type Test(...); 

しかし、私は引数がこのSNFIAEの仕事を作る方法を理解していませんよ。私は、引数を削除することができるはずとテンプレートの選択は全く同じように働くように思える:

template<typename R, typename S = decltype(declval<R>().test())> static true_type Test(); 
template<typename R> static false_type Test(); 

をしかし、それは、私が取得していません:テスト」オーバーロードされたの

コール( ) 'があいまいです

このSFINAEを動作させるために、これらの引数についてはどういう意味ですか?

答えて

3

デフォルトのテンプレートタイプの引数は関数シグネチャの一部ではないため、同じシグネチャのTestの2つのオーバーロードがあるため、2番目の例はコンパイルに失敗します。それは許されない。

あなたの最初の例では、followignのように動作します。

タイプRはそれで機能testを持っている、両方のTestなる有効な過負荷候補を。ただし、省略関数は省略記号以外の関数よりもランクが低く、したがってコンパイラは最初のオーバーロードを選択し、true_typeを返します。

Rがそれにtestを持っていない、最初のオーバーロードは、オーバーロードの解決セット(作品でSFINAE)から除外されます。あなたはfalse_typeを返す2番目のものだけが残っています。

+0

しかし、それを超えて、それらが正しい順序で評価されるようになり、これらの引数の型について特別な何かがあります。私はなぜコンパイラが 'R *'を '...'に好むのか理解していません。あなたはそれを説明できますか? –

+0

@ JonathanMeeは、答えに追加されます。 – SergeyA

+0

@JonathanMee単純に言えば、(...)は、オーバーロード解決を実行する際に、引数リストとの最も優先順位の低い一致です。これは設計によるものであり、標準で義務づけられています。偶然、それはまた、だから私はいつも面白い...私の2番目の引数として省略記号を使用して、コンパイラの好みを強制することができ –

1

質問が回答されているが、多分それはより深い説明に入ると便利です。

うまくいけば、この注釈付きのプログラムは、物事をより明確になります。

#include <utility> 
#include <iostream> 

// define the template function Test<R> if and only if the expression 
// std::declval<R>().test() 
// is a valid expression. 
// in which case Test<R, decltype(std::declval<R>().test())>(0) will be preferrable to... (see after) 
template<typename R, typename S = decltype(std::declval<R>().test())> 
    static std::true_type Test(R*); 

// ...the template function Test<R>(...) 
// because any function overload with specific arguments is preferred to this 
template<typename R> static std::false_type Test(...); 


struct foo 
{ 
    void test(); 
}; 

struct bar 
{ 
    // no test() method 
// void test(); 
}; 


// has_test<T> deduces the type that would have been returned from Test<T ... with possibly defaulted args here>(0) 
// The actual Test<T>(0) will be the best candidate available 
// For foo, it's Test<foo, decltype(std::declval<R>().test())>(foo*) 
// which deduces to 
// Test<foo, void>(foo*) 
// because that's a better match than Test<foo>(...) 
// 
// for bar it's Test<bar>(...) 
// because Test<bar, /*error deducing type*/>(bar*) 
// is discarded as a candidate, due to SFNAE 
// 
template<class T> 
constexpr bool has_test = decltype(Test<T>(0))::value; 


int main() 
{ 
    std::cout << has_test<foo> << std::endl; 
    std::cout << has_test<bar> << std::endl; 
} 
関連する問題