4

C++11での転送方法を理解しています。

template <class T> void foo(T &&)

foo は、左辺値と右辺値の両方を受け入れるようになりました。

私の問題は、さらに foo をオーバーロードするときです。次の簡単なコードを検討してください。

template <class T> class A {};

template <class T> void foo(T &&obj) {}
template <class T> void foo(A<T> &&obj) {}

int main() {
  int i;
  A<int> a;
  foo(i); // calls foo(T &&) as I want
  foo(a); // calls foo(T &&), but I want it to call foo(A<T> &&)
  return 0;
}

(左辺値) オブジェクトで呼び出すと、 ではなく が呼び出さfooれます。の定義では、 std とカスタム トレイトでisかどうかを区別することができましたが、からメソッドを呼び出す必要があり、 asではなく として宣言されているため、非常に厄介なコードが生成されます。宣言を並べ替えたり、左辺値のオーバーロードを追加したりしても、問題は解決しません。A < int > &foo(T &&)foo(A < T > &&)foo(T &&obj)objA<T>AobjobjTA < T >

私が自分自身を理解したことを願っています。問題を特定するために、簡略化されたコードを提供しました。カスタムOptional < T >クラス ( に類似) を実装していますが、別の、、またはオブジェクトからオブジェクトboost::optionalを作成 (および割り当て) できるようにする必要があるため、コンストラクターでこの問題が発生しています。(ここで、 は作成するオプション オブジェクトが保持する型であり、は別の型であり、 に変換可能です)。Optional < T >Optional < T >Optional < U >TUTUT

お時間をいただきありがとうございます。

4

1 に答える 1

6

関数呼び出しのテンプレート引数推定中に、「ユニバーサル参照」の特別な規則は、パラメーターの型が cv 修飾されていないテンプレート パラメーター [temp.deduct.call]/3 である場合にのみ適用されます。

[Pは関数テンプレートのパラメーターの型で、Aは引数の型です]

が cv 修飾されていないテンプレート パラメーターへの右辺値参照であり、引数が左辺値である場合P、型推定の代わりに「左辺値参照A」が使用されAます。【例:

template <class T> int f(T&&);
template <class T> int g(const T&&);
int i;
int n1 = f(i); // calls f<int&>(int&)
int n2 = f(0); // calls f<int>(int&&)
int n3 = g(i); // error: would call g<int>(const int&&), which
// would bind an rvalue reference to an lvalue

終了例]

同様に、これらの規則はパラメーター type には適用されませんA<T>&&。これは「ユニバーサル参照」ではなく、純粋に右辺値参照型です。


-version がより特殊化されている (より一致する) 2 つのコンストラクターの間でランキングを取得したい場合はA<T>、次のことができます。

  • 2 つの3 つのオーバーロード(ありがとう、A<T> const&Eric Niebler ) を提供し、一般的なバージョンに加えてA<T>&A<T>&&T&&
  • SFINAE を使用します。パラメーターを使用して 2 つのオーバーロードを提供し、が特殊化されているT&&かどうかを確認しますTA<T>
于 2013-11-03T23:41:36.463 に答える