copy関数とストリームイテレータを使った一行出力コード

以前とある記事でコメントを頂いたときにこんなコードが書いてありました。

std::copy(xs.begin(), xs.end(), std::ostream_iterator<int>(std::cout, ","));

当時は全然意味がわからなかったのでとりあえずスルーしてたのですが、ストリームイテレータSTL配列操作テンプレート関数の学習を経て、ようやく読めるようになりました。

まずはcopy関数から見てみましょう。

ある配列を別の配列にコピーするための関数です。

#include <iostream>
#include <algorithm>
using namespace std;

int main () {
    int data1[] = {10,20,30};
    int data2[3];
    
    // data1の全ての要素をdata2へコピー
    copy(data1,data1+3,data2);
    
    for(int i=0;i<3;++i){
        cout << data2[i] << endl;
    }
    
    return 0;
}
$ main
10
20
30

もちろん他の関数と同じく、イテレータを渡すこともできます。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main () {
    vector<int> data1;
    vector<int> data2;
    
    data1.push_back(10);
    data1.push_back(20);
    data1.push_back(30);
    
    // data2への挿入イテレータを用意
    back_insert_iterator<vector<int>> iit_data2( data2 );
    
    // data1の全ての要素をdata2へコピー
    copy(data1.begin(),data1.end(),iit_data2);
    
    vector<int>::iterator it  = data2.begin();
    vector<int>::iterator end = data2.end();
    for(;it!=end;++it) {
        cout << *it << endl;
    }
    
    return 0;
}
$ main
10
20
30

ばっちりコピーが動いていますね。

さて冒頭の処理に戻ります。

std::copy(xs.begin(), xs.end(), std::ostream_iterator<int>(std::cout, ","));

これはつまり、xsのデータをostream_iteratorで得たイテレータにコピーしているという処理になります。

そしてostream_iteratorというのは出力ストリームイテレータなので画面にxsの内容が出力されるということになります。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main () {
    vector<int> xs;
    
    xs.push_back(10);
    xs.push_back(20);
    xs.push_back(30);
    
    copy(xs.begin(),xs.end(),ostream_iterator<int>(cout,"\n"));
    
    return 0;
}
$ main
10
20
30

コードがとてもスッキリしましたね。

ある配列やイテレータのデータの中身を出力したいだけの処理を書く場合、このやり方を使えば楽に書けそうですね。

ただこの書き方って一般的によく使われるような処理なのかどうかはちょっとわかりませんが。