C++で,複数の列からそれら各要素の同一インデックス同士の組を要素に持つ列を構成するzipを作ってみる.
手元の環境の制約からC++14上の実装を考えます.
もちろん,C++11でも,もっと新しい規格でもよいのですが…
とりあえず,まず始めに作成したコードはこれ1,2です.まだ未完成です.
コピーするのが面倒なので,リンクを貼るだけにします.
目標
まず,引数を可変長にしたいですね.
それと,できるだけコピーや一時的なオブジェクトの生成を減らしたいです.
多くの場合,zipの結果を使用する場面は,演算のフローが明確な場合が多いと思います.
簡単な例を挙げると,
for (auto&& t : zip(xs, ys, zs)) {
const auto& x = std::get<0>(t);
const auto& y = std::get<1>(t);
auto& z = std::get<2>(t);
z = f(x, y);
}
こんな感じかと思います.
作成コードには,参照方法が異なる3つのパターンを作成しました.
名前空間lref
は,左辺値参照で列を受け取ります.
zip
内では,std::tie
を使用して左辺値参照型を要素に持つstd::tuple
型が要素のstd::vector
を作ります.
このzip
は右辺値参照を取ることができません.
そのため,
auto a = zip(xs, zip(ys, zs));
こういったネストするような呼び出しのコードは書けません.
次のような書き方はOKです.
auto b = zip(ys, zs);
auto a = zip(xs, b);
今のところネスト呼び出しの必要性はありません.
そのため,引数の個数を可変長にする事を優先しようと思いますが…
どうやってパックしたり展開すればよいのか,すぐに思い付きません…
TODO
- 引数を可変長にする.
- できるだけコピーや一時オブジェクトの数を減らす.
- 右辺値参照を受け取れるようにする.
引数を可変長にするには,std::tuple
の各要素に対してoperator*
やoperator++
を呼び,かつ返り値のstd::tuple
で補足して返す関数があれば良さそう.
でも,どうやって定義するんだ?
また,色々書いてみた2が,この実装はコンパイルは通るが実行時エラーになってしまう…
コンパイル時zip
zipの対象となる列が全てstd::array
ならば,constexpr関数として定義できるそうだ3.
つまり,それ以外,例えばstd::vector
を使用する限り,やはり,何らかのコピーや一時オブジェクトの生成は避けられないという事なのかもしれない.
参考情報
- C++14(17) で zip 書いてみた - Secret Garden(Instrumental)
- c++でzip関数を実装してみた. C++17の構造化束縛と闇テンプレートを使って. - Qiita