最終更新日時: 2025年07月10日 10時26分30秒 (JST)
Koichi Murase が更新

履歴 編集

# 初期化式をともなう範囲for文 [P0614R1](C++20)

このページはC++20に採用された言語機能の変更を解説しています。

のちのC++規格でさらに変更される場合があるため関連項目を参照してください。

## 概要

if文、switch文、for文と同様に、範囲for文でもそのスコープで使用する変数の初期化ができるよう構文を追加する。

これにより、範囲for文で使用するための変数を、範囲for文のスコープ外 (前) で宣言しなくてもよくなり、範囲for文用の変数のスコープを限定できるようになる。

従来の範囲for文で記述していた以下のようなプログラムは、

    {
      T thing = f();
      for (auto& x : thing.items()) {
        // 注: "for (auto& x : f().items())" のように書いてはならない
        mutate(&x);
        log(x);
      }
    }

C++20では、初期化式をともなう範囲for文を使用して、以下のように記述できる：

    for (T thing = f(); auto& x : thing.items()) {
      mutate(&x);
      log(x);
    }

また同様に、範囲for文にインデックスを持たせる以下のようなプログラムは、

    {
      std::size_t i = 0;
      for (const auto& x : foo()) {
        bar(x, i);
        ++i;
      }
    }

C++20では以下のように記述できる：

    for (std::size_t i = 0; const auto& x : foo()) {
      bar(x, i);
      ++i;
    }

## 仕様

新たな範囲for文の構文は、以下の通り：

    init-statement:
      expression-statement
      simple-declaration

    iteration-statement:
      for ( init-statement opt for-range-declaration : for-range-initializer ) statement

この改定では、範囲for文に初期化式であるinit-statement (セミコロン含む) が省略可能として追加になる。

範囲for文のfor文への展開は以下のようになる：

    {
      init-statement opt
      auto &&__range = for-range-initializer ;
      auto __begin = begin-expr ;
      auto __end = end-expr ;
      for ( ; __begin != __end; ++__begin ) {
        for-range-declaration = *__begin;
        statement
      }
    }

## 例

    #include <iostream>
    #include <vector>

    class X {
      std::vector<int> data_ = {1, 2, 3};
    public:
      std::vector<int>& items() { return data_; }
    };

    X foo() { return X{}; }

    int main()
    {
      for (auto thing = foo(); auto& x : thing.items()) {
        // 要素を書き換えた結果を使ってなにかする
        ++x;
        std::cout << x << std::endl;
      }
    }

### 出力

    2
    3
    4

## 関連項目

- C++17 if文とswitch文の条件式と初期化を分離
- C++23 初期化文での型の別名宣言を許可

## 参照

- P0614R1 Range-based for statements with initializer