C++11:範囲for文
C++11では、ある範囲内の全要素の処理を簡潔に書けるようになった。
for ( auto x : 範囲 ) { // ... }
「範囲」は、std::vectorのように反復子を返すメンバー関数begin()/end()が定義されているクラスのオブジェクトでも良いし、組み込み配列のように非メンバー関数begin()/end()を適用できるオブジェクトでも良い。(メンバー関数の方が優先される。)
void func(std::vector<double> &v) { for ( auto x : v ) std::cout << x << "\n"; // 要素はxにコピーされる for ( auto &x : v ) ++x; // 要素を参照すると更新できる for ( const auto x : {1,2,5,13,34} ) std::cout << x << "\n"; }
int v[] = {1,2,5,13,34}; for ( auto x : v ) std::cout << x << "\n";
範囲for文を支援するために、標準ライブラリの<iterator>で範囲アクセス関数std::begin()/std::end()が定義されている。
namespace std { // クラス用 template<typename C> auto begin(C &c) -> decltype(c.begin()); template<typename C> auto begin(const C &c) -> decltype(c.begin()); template<typename C> auto end(C &c) -> decltype(c.end()); template<typename C> auto end(const C &c) -> decltype(c.end()); // 組み込み配列用 template<typename T, size_t N> auto begin(T (&array)[N]) -> T*; template<typename T, size_t N> auto end(T (&array)[N]) -> T*; }
つまり、冒頭の範囲for文は以下のコードと等価である。
for ( auto __begin = begin(範囲), __end = end(範囲); __begin != __end; ++__begin ) { auto x = *__begin; // ... }
範囲アクセス関数を直接使うことはあまりないだろうが、呼び出し方には注意が必要だ。
#include <algorithm> #include <iterator> template<typename Range, typename Function> void for_each_all(Range &range, Function func) { // 組み込み配列へ対応するために、using宣言する必要がある。 using std::begin; using std::end; // 非標準の範囲アクセス非メンバー関数へ対応するために、名前空間修飾無しで呼び出す必要がある。 auto first = begin(range); auto last = end(range); std::for_each(first, last, func); } #include <cstddef> struct MyContainer { static constexpr std::size_t m_a_size = 3u; int m_a[m_a_size]; MyContainer() : m_a{4, 5, 6} {} }; int *begin(MyContainer &c) { return c.m_a; } int *end(MyContainer &c) { return c.m_a + MyContainer::m_a_size; } #include <iostream> #include <vector> void print_line(int i) { std::cout << i << "\n"; } int main() { std::vector<int> v = {1, 2, 3}; MyContainer c; int a[] = {7, 8, 9}; for_each_all(v, print_line); for_each_all(c, print_line); for_each_all(a, print_line); }
(高橋氏の記事の「std名前空間のbegin()/end()をusing宣言しているのは、配列版を考慮するため。」という説明は、よくわからなかった。)
参考
- range-for statement(範囲 for 文)
- std::beginとstd::endの使い方 - Faith and Brave - C++で遊ぼう
- 作者: ビャーネ・ストラウストラップ,Bjarne Stroustrup,柴田望洋
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2015/02/28
- メディア: 大型本
- この商品を含むブログ (8件) を見る