目次
はじめに
C++で、「vector
に格納された数値全てを2倍したい」「文字列のリストを全て大文字にしたい」といったように、コンテナの各要素に同じ変換処理を加え、その結果を新しいコンテナに格納したい場面は非常に多くあります。
for
ループを書いて一つずつ処理することもできますが、C++の標準ライブラリには、この目的のための、より表現力豊かで効率的なツールが用意されています。
std::transform
(<algorithm>
): 伝統的なアルゴリズム関数。std::views::transform
(<ranges>
): C++20で導入された、よりモダンで宣言的な方法。
この記事では、これら2つの transform
の使い方を、サンプルコードと共に解説します。
1. std::transform
アルゴリズム (C++98〜)
std::transform
は、<algorithm>
ヘッダーで提供される関数で、入力範囲の各要素に指定した関数を適用し、その結果を出力範囲に書き込みます。
サンプルコード
#include <iostream>
#include <vector>
#include <string>
#include <algorithm> // transform
#include <iterator> // back_inserter
using namespace std;
int main() {
vector<int> source_numbers = {10, 20, 30, 40};
vector<int> destination_numbers;
// 1. 変換処理を定義 (ラムダ式)
auto multiply_by_10 = [](int n) { return n * 10; };
// 2. transformを呼び出し
transform(source_numbers.begin(), source_numbers.end(),
back_inserter(destination_numbers),
multiply_by_10);
// 3. 結果を出力
cout << "変換後の数値: ";
for (int n : destination_numbers) {
cout << n << " ";
}
cout << endl;
return 0;
}
解説
transform(入力開始, 入力終了, 出力開始, 変換処理)
: 4つの引数を取ります。source_numbers.begin(), source_numbers.end()
: 変換したい元のコンテナの範囲。back_inserter(destination_numbers)
: 結果を書き込む先のイテレータ。back_inserter
は、destination_numbers
の.push_back()
を呼び出す特殊なイテレータを生成します。multiply_by_10
: 各要素に適用する変換処理(この例では10倍するラムダ式)。
2. std::views::transform
レンジアダプタ (C++20)
C++20のRangesライブラリは、より宣言的で組み合わせやすい transform
を提供します。これは、元のコンテナを変換する「ビュー」を作成するもので、遅延評価されるため非常に効率的です。
サンプルコード
#include <iostream>
#include <vector>
#include <ranges> // views::transform
namespace views = std::ranges::views;
int main() {
std::vector<int> source_numbers = {10, 20, 30, 40};
// パイプ(|)でコンテナとtransformビューを繋ぐ
auto transformed_view = source_numbers | views::transform([](int n) { return n * 10; });
cout << "変換後の数値: ";
// ビューを直接ループ処理できる
for (int n : transformed_view) {
cout << n << " ";
}
cout << std::endl;
return 0;
}
解説
source_numbers | views::transform(...)
: パイプ演算子|
を使って、source_numbers
の各要素をtransform
に渡す、というデータの流れを直感的に記述できます。transformed_view
: この変数は、変換後の値を持つ新しいvector
ではありません。source_numbers
を「10倍して眺める」という設定情報を持つ、軽量なビューオブジェクトです。実際に10倍する計算は、for
ループで要素が必要になった時点で行われます(遅延評価)。
まとめ
今回は、コンテナの全要素を変換するための transform
について、伝統的なアルゴリズムと、C++20のRangesライブラリの2つの方法を解説しました。
std::transform
: イテレータをベースにした伝統的な方法。結果を別のコンテナに格納する必要がある。std::views::transform
: C++20のRangesによるモダンな方法。パイプ構文で直感的に記述でき、遅延評価により効率的。
C++20以降の環境では、コードの可読性と効率性の両面から、views::transform
を使うのがベストプラクティスです。