3

コピーを避けたいテンプレートクラスがあります(そうするための潜在的なコストのため)。移動コンストラクターを実装できますが、「テンプレートパラメーター間」の移動も許可したいと思います。これが私がコンパイルしようとしているものです:

template <class T>
class Foo
{
public:
    Foo() {}
    template <class U> Foo(Foo<U>&&) {}

private:
    Foo(const Foo&);
};

Foo<int> f() { Foo<float> y; return move(y); }
Foo<int> g() { Foo<int> x; return x; }
Foo<int> h() { Foo<float> z; return z; }

技術的にfがコンパイルされる理由を理解しています。move(y)のタイプはFoo(float)&&であり、Foo(U)&&を受け取る便利なコンストラクターがあるため、コンパイラーはU=floatが機能することを確認できます。

hはコンパイルされません。zはFoo(float)型であり、U = floatが選択されている場合にmoveコンストラクターを呼び出すことができることを理解するにはFoo(U)&&から遠すぎると思います...

gがコンパイルされる理由はわかりませんが、コンパイルされます。xの型はFoo(int)です。コンパイラはどのようにムーブ演算子を使用することができますか(Foo(int)からFoo(int)&&に暗黙的にキャストすることはできませんか?)

だから私の質問は:ルールは何ですか?なぜhはコンパイルされるのに、gはコンパイルされないのですか?hをコンパイルするためにFooで変更できるものはありますか?

ありがとうございました

4

1 に答える 1

7

コピーまたは移動コンストラクターをテンプレートにすることはできません。12.8(2、3)から:

クラスの非テンプレートコンストラクターは、最初のパラメーターが、、、またはの型であり、他のパラメーターがないか、他のすべてのパラメーターにデフォルトの引数(8.3.6)があるX場合、コピーコンストラクターです。[例:とはコピーコンストラクタです。]X&const X&volatile X&const volatile X&X::X(const X&)X::X(X&,int=1)

クラスの非テンプレートコンストラクターは、最初のパラメーターがタイプ、、、、または、であり、他のパラメーターがないか、他のすべてのパラメーターにデフォルトの引数(8.3.6)があるX場合、移動コンストラクターです。[例:移動コンストラクターです。]X&&const X&&volatile X&&const volatile X&&Y::Y(Y&&)

つまり、通常のコンストラクター( move -constructorではない)を呼び出しているため、例fg作業を行います。

fmove(y)の結果はにバインドできるため、明らかな理由で機能しFoo<float>&&ます。g別の理由xで機能します。の型は関数の戻り型と同じであるためx、returnステートメントの式の値はに一致しFoo<int>&&ます。これは12.8(31、32)のためです:

クラス戻り型を持つ関数のステートメントで、式が関数戻り型と同じcv-unqualified型を持つreturn不揮発性自動オブジェクト(関数またはcatch-clauseパラメーター以外)の名前である場合、[ ...]

ソースオブジェクトが関数パラメーターであり、コピーされるオブジェクトが左辺値で指定されていることを除いて、コピー操作の省略基準が満たされている、または満たされる場合、コピーのコンストラクターを選択するためのオーバーロード解決は次のようになります。最初は、オブジェクトが右辺値で指定されているかのように実行されます。

最後に、なぜh機能しないのかがわかります。ステートメントの式の値は、明示的にキャストされていないため(を介して)、または12.8(32)節の特別な分与が与えられていないため、その型が同じではないため、にバインドできzません。関数の戻り型として。(バインドできるのは(ほぼ間違いなく間違っている)またはにのみです。)returnFoo<float>&&std::moveFoo<float>&Foo<float> const &


ちなみに、外部リソース(プリミティブなど)を管理しないオブジェクトを移動する意味はありません。とにかく実際のオブジェクトデータをコピーする必要があります。

于 2012-06-14T08:04:28.593 に答える