次期C++2b(C++23)標準ライブラリのコルーチンサポート型std::generator<Ref>(→id:yohhoy:20220801)の第1テンプレートパラメータRefと、オブジェクトのコピー/ムーブの関係性についてメモ。
まとめ:
- 利用側にconst参照を提供:const-lvalue参照
const T&を指定。 - 利用側に可変参照を提供:lvalue参照
T&を指定。 - ムーブのみ(Move-only)型:値型
Tまたはrvalue参照型T&&を指定。- 実動作は両者で同一。“ムーブ” 動作を示唆する
T&&の方が好ましい?
- 実動作は両者で同一。“ムーブ” 動作を示唆する
- プリミティブ型など*1:値型
Tを指定。 - 利用側の範囲for:
auto&&(→id:yohhoy:20120609)またはconst auto&を推奨。
テンプレートパラメータRefに値型Tまたはその参照型を指定した場合*2、各箇所において発生するコピー/ムーブは下表のとおり:
| Ref | yield-v | yield-cv | yield-rv | consume-v |
|---|---|---|---|---|
T |
1 copy | 1 copy | 0 | 1 move |
T&& |
1 copy | 1 copy | 0 | 1 move |
T& |
1 copy | 1 copy | (ill-formed) | 1 copy |
const T& |
0 | 0 | 0 | 1 copy |
凡例:0=コピー/ムーブなし、(ill-formed)=コンパイルエラー
// C++2b #include <generator> // ユーザ定義コルーチン std::generator<??> gen() { T v; co_yield v; // yield-v const T cv; co_yield cv; // yield-cv // yield-rv co_yield T{}; co_yield std::move(v); } // 利用側コード void consumer() { // consume-v for (auto v: gen()) { ... } // 下記2パターンは常にコピー/ムーブ発生しない for (const auto& cr: gen()) { ... } for (auto&& ur: gen()) { ... } }
ノート:コルーチン内でco_yield std::move(v);を記述しても、即座にはムーブ処理が行われないことに留意。Ref=T/T&&であれば利用側コードでムーブ処理が行われる。
関連URL