2017-02-06 22 views
3

は、コードのこの部分を考えてみましょう:あいまいな呼び出しを再帰的に可変引数テンプレート関数のオーバーロードを呼び出す

template<typename FirstArg> 
void foo() 
{ 
} 

template<typename FirstArg, typename... RestOfArgs> 
void foo() 
{ 
    foo<RestOfArgs...>(); 
} 

int main() 
{ 
    foo<int, int, int>(); 
    return 0; 
} 

RestOfArgsが一つだけの要素({int})を持っているとき、それが原因あいまいな呼び出しfoo<RestOfArgs...>();にコンパイルされません。

しかし、これはエラーなしでコンパイル:

template<typename FirstArg> 
void foo(FirstArg x) 
{ 
} 

template<typename FirstArg, typename... RestOfArgs> 
void foo(FirstArg x, RestOfArgs... y) 
{ 
    foo(y...); 
} 

int main() 
{ 
    foo<int, int, int>(5, 6, 7); 
    return 0; 
} 

なぜ最初のケースで曖昧さはありますか?

なぜ2番目のケースではあいまいさがありませんか?

+0

私の仮定は、それはとは何かを持っているということです関数の署名がその引数であるという事実と、 ''と' 'はあるケースでは区別できませんが、他のケースでは区別できません。 – yeputons

+0

[overload_resolution](http://en.cppreference.com/w/cpp/language/overload_resolution)、[Function_template_overloading](http://en.cppreference.com/w/cpp/language/function_template#Function_template_overloading)を参照してください。 ) – Jarod42

+0

@ Jarod42私はそれを見ましたが、私の質問に対する答えはまだ分かりません。 –

答えて

1

なぜ最初のケースではあいまいさがありますか?

RestOfArgsは空でもかまいません。

のでfoo<int>をとしてインスタンス化することができます両方がコンパイルされますので、それが曖昧な

template<int> 
void foo() 
{ 
} 

template<int,> 
void foo() 
{ 
    foo<>(); 
} 

実際にはfoo<>()はコンパイルされませんが、次のインスタンス化では失敗するため、問題はありません。

なぜ2番目のケースであいまいさはありませんか?

foo<int>(7)はとしてインスタンス化することができる。

template<int> 
void foo(int 7) 
{ 
} 

template<int> 
void foo(int 7) 
{ 
    foo(); 
} 

しかし引数を取るいいえfooが存在しないため、もう一つは、エラーであるため、唯一の候補が最初であります1つ、したがってあいまいではありません

+0

[この例](http://ideone.com/ZQz8Le)についても説明しますか?私は 'foo'呼び出しを削除しましたが、まだコンパイルされています。 – yeputons

+0

@yeputons再帰呼び出しなしでは、VAARGテンプレートのみが使用されています。 –

+0

@yeputons、SOをコンサルティングサービスとして使用しないでください。これはあなたの質問に対する良い答えです。他に関連する質問がある場合は、別の質問を投稿してください。 –

0

The answer by @ZangMingJieあなたのコードで観察している動作の違いに答えます。

私はそれが簡単に次のように変更して名前解決を理解することが分かっ:

template<typename FirstArg> 
void foo() 
{ 
    printf("1\n"); 
} 

template<typename FirstArg, typename SecondArg, typename... RestOfArgs> 
void foo() 
{ 
    printf("2\n"); 
    foo<SecondArg, RestOfArgs...>(); 
} 

int main() 
{ 
    foo<int, int, int>(); 
    return 0; 
} 

二つ以上のテンプレートパラメータが使用されているがある場合には、第二の機能が呼び出されます。 1つのテンプレートパラメータがある場合、最初の関数が呼び出されます。 Function template overloading

+0

これは動作し、あいまいさの問題を解決しますが、私はまだなぜそれがわかりません。私の元の質問はまだ答えられていない。 –

+0

@rubix_addict、私はZangの答えがその問題を説明したと思った。 –

+0

@RSahu:私は彼が説明するように、関数の定義の内容に関するSFINAEが使用されるとは思わしくありません。 -/ – Jarod42

1

(与えられたパラメータに基づいて)、より特化されたテンプレート機能伝えるためのルールがたくさんあります。

foo<int>()ための曖昧

template<typename> void foo(); 
template<typename, typename...> void foo(); 

を作るポイント、しかしfoo(42)のためではない

template<typename T> void foo(T); 
template<typename T, typename... Ts> void foo(T, Ts...); 

は以下の通りです:

In case of a tie, if one function template has a trailing parameter pack and the other does not, the one with the omitted parameter is considered to be more specialized than the one with the empty parameter pack.

+0

この文章では、両方のケースであいまいさがあってはならないと示唆していませんか?まあ、 "後続のパラメータパック"はちょっとあいまいです(意図しない言い訳) - "後続のテンプレートパラメータパック"と "後続の関数パラメータパック"の両方に適用できます。 –

+0

私はそれが十分なIMOではないことに同意しますが、 'trailing 'は' template void f(先行、std :: tuple 、末尾) 'vs 'template void f(A、std :: tuple <>、B)'です。これはあなたのケースに似ています。 – Jarod42

+0

私の両方のケースでは、パラメータパックは「後ろに」 –

関連する問題