10

2つのオーバーロードされた関数があります。1つはL値を取り、もう1つはR値を取ります。目的は、関数を次のように呼び出すことができるようにすることです。

Obj obj;
foo(obj);

また:

foo(Obj());

だから、私は2つのオーバーロードされた関数を書きます:

template <class T>
void foo(T& v)
{
  /* ... function body code goes here ... */
}

template <class T>
void foo(T&& v)
{
    foo(v);
}

int main()
{
    foo(int(5));
}

R値の過負荷は、L値の過負荷に委任する必要があるだけです。私がそれを理解する方法では、関数の本体に入ると、特にまたはvを使用しない限り、を使用するとL値の参照が得られます。したがって、R値のオーバーロード内で呼び出すと、(繰り返しではなく)L値のバージョンが自動的に呼び出されます。std::movestd::forwardfoo(v)

しかし、コンパイラはあいまいさについて不平を言います。

test.cpp: In function ‘void foo(T&&) [with T = int]’:
test.cpp:305:12:   instantiated from here
test.cpp:299:2: error: call of overloaded ‘foo(int&)’ is ambiguous

なぜこれが曖昧なのかわかりません。R値のオーバーロード内での呼び出しfoo()は、L値バージョンを明確に呼び出す必要があります。では、なぜこれはコンパイルされないのですか?

4

1 に答える 1

6

短いバージョン:コンパイラを更新してみてください。お使いのバージョンはhttp://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1164を実装していません。

2番目のテンプレートは「完全転送」テンプレートです。タイプがT&&、テンプレートパラメータである関数テンプレートパラメータは、引数が右辺値の場合、および引数が左辺値の場合に、TそのテンプレートパラメータをX(引数の型は)に推定します。XX&

あなたの場合、あなたは右辺値を渡したので、(そしてあなたの実際のコードでは)Tに推論されました。変数名または左辺値である他の何かを渡した場合、2番目のテンプレートはパラメータータイプを持ちます(Tは、であり、そのようなタイプに適用されます)。ObjintObj&Obj&&&Obj&

しかし、他のテンプレートにもそのようなパラメータタイプがあります。したがって、過負荷の解決中、引数のパラメーターへの変換は同じ(完全一致)であり、半順序規則の下で、2つのテンプレートの特異性という別の基準を検査する必要があります。一方のテンプレートがもう一方のテンプレートよりも特殊化されている場合は、コンパイラーによって選択されます。他のテンプレートよりも専門的なテンプレートがない場合、最終的なあいまいさが生じます。

この場合、最初のテンプレートは2番目のテンプレートよりも特殊化されているため、コンパイラーは最初のテンプレートを最終的に呼び出す必要があります。

于 2012-07-24T06:54:22.733 に答える