25

次のコードでcould not deduce template argument for Tエラーが発生したことに驚きました。

struct foo
{
  template <typename T>
  void bar(int a, T b = 0.0f)
  {
  }
};

int main()
{
  foo a;
  a.bar(5);

  return 0;
}

呼び出すa.bar<float>(5)と問題が修正されます。コンパイラがデフォルトの引数から型を推測できないのはなぜですか?

4

3 に答える 3

20

C ++ 03では、仕様により、デフォルトの引数を使用してテンプレート引数を推測することが明示的に禁止されています(C++03§14.8.2/17)。

テンプレートのtype-parameterは、関数のデフォルト引数の型から推測することはできません。

C ++ 11では、関数テンプレートのデフォルトのテンプレート引数を指定できます。

template <typename T = float>
void bar(int a, T b = 0.0f) { }

ただし、デフォルトのテンプレート引数は必須です。デフォルトのテンプレート引数が指定されていない場合でも、デフォルトの関数引数はテンプレート引数の推定に使用できません。具体的には、以下が適用されます(C ++ 11 14.8.2.5/5)。

推定されないコンテキストは次のとおりです。

..。

  • 引数の推定が行われている呼び出しで使用されているデフォルトの引数を持つ関数パラメーターのパラメーター型で使用されるテンプレートパラメーター。
于 2012-03-09T04:36:47.127 に答える
16

一般的にそれを達成することにはいくつかの技術的な困難があります。テンプレートのデフォルトの引数は、必要になるまでインスタンス化されないことに注意してください。次に考えてみましょう:

template<typename T, typename U> void f(U p = T::g());  // (A)
template<typename T> T f(long, int = T());  // (B)
int r = f<int>(1);

これは、(とりわけ)次の手順を実行することによって今日解決されます。

  1. attempt to deduce template parameters for candidates (A) and (B); this fails for (A), which is therefore eliminated.
  2. perform overload resolution; (B) is selected
  3. form the call, instantiating the default argument

In order to deduce from a default argument, that default argument would have to be itself instantiated before completing the deduction process. That could fail, leading to errors outside the SFINAE context. I.e., a candidate that may be entirely inappropriate for a call could trigger an error.

于 2015-09-04T17:27:21.317 に答える
4

正当な理由はそれかもしれません

void foo(bar, xyzzy = 0);

オーバーロードのペアに似ています。

void foo(bar b) { foo(b, 0);  }
foo(bar, xyzzy);

さらに、次のようにリファクタリングすると有利な場合があります。

void foo(bar b) { /* something other than foo(b, 0); */ }
foo(bar, xyzzy);

1つとして記述された場合でも、1つに2つの関数が含まれているようなものであり、どちらもどのような意味でも「優先」されません。1つの引数の関数を呼び出しています。2つの引数の1つは、事実上異なる関数です。デフォルトの引数表記は、それらを1つにマージするだけです。

オーバーロードが要求されている動作をする場合、一貫性を保つために、テンプレートが2つの定義に分割されている場合に機能する必要があります。推論は、呼び出されていない無関係の関数から型をプルすることになるため、それは意味がありません。また、実装されていない場合は、さまざまなパラメータリストの長さをオーバーロードすると、「デフォルトの引数」と比較して「二級市民」になることを意味します。

オーバーロードとデフォルトの違いがクライアントに完全に隠されていると便利です。

于 2012-03-09T04:55:02.273 に答える