【C++】std::transform でコンテナの全要素を変換する方法

目次

はじめに

C++で、「vectorに格納された数値全てを2倍したい」「文字列のリストを全て大文字にしたい」といったように、コンテナの各要素に同じ変換処理を加え、その結果を新しいコンテナに格納したい場面は非常に多くあります。

forループを書いて一つずつ処理することもできますが、C++の標準ライブラリには、この目的のための、より表現力豊かで効率的なツールが用意されています。

  1. std::transform (<algorithm>): 伝統的なアルゴリズム関数。
  2. 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 を使うのがベストプラクティスです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次