# 清洁的方法来写多个“for”循环

` `vector< vector< vector<int> > > A; for (int k=0; k<A.size(); k++) { for (int i=0; i<A[k].size(); i++) { for (int j=0; j<A[k][i].size(); j++) { do_something_on_A(A[k][i][j]); } } } double B[10][8][5]; for (int k=0; k<10; k++) { for (int i=0; i<8; i++) { for (int j=0; j<5; j++) { do_something_on_B(B[k][i][j]); } } }` `

` `class Matrix3D { int x; int y; int z; std::vector<int> myData; public: // ... int& operator()( int i, int j, int k ) { return myData[ ((i * y) + j) * z + k ]; } };` `

` `class Matrix3D { // as above... typedef std::vector<int>::iterator iterator; iterator begin() { return myData.begin(); } iterator end() { return myData.end(); } };` `

` `for ( Matrix3D::iterator iter = m.begin(); iter != m.end(); ++ iter ) { // ... }` `

（要不就：

` `for ( auto& elem: m ) { }` `

` `class Matrix3D { // ... class iterator : private std::vector<int>::iterator { Matrix3D const* owner; public: iterator( Matrix3D const* owner, std::vector<int>::iterator iter ) : std::vector<int>::iterator( iter ) , owner( owner ) { } using std::vector<int>::iterator::operator++; // and so on for all of the iterator operations... int i() const { ((*this) - owner->myData.begin()) / (owner->y * owner->z); } // ... }; };` `

` `for (auto& k : A) for (auto& i : k) for (auto& j : i) do_something_on_A(j);` `

` ` template <typename Container, typename Function> void for_each3d(const Container &container, Function function) { for (const auto &i: container) for (const auto &j: i) for (const auto &k: j) function(k); } int main() { vector< vector< vector<int> > > A; for_each3d(A, [](int i){ std::cout << i << std::endl; }); double B[10][8][5] = { /* ... */ }; for_each3d(B, [](double i){ std::cout << i << std::endl; }); }` `

` ` template <typename T> struct has_iterator { template <typename C> constexpr static std::true_type test(typename C::iterator *); template <typename> constexpr static std::false_type test(...); constexpr static bool value = std::is_same< std::true_type, decltype(test<typename std::remove_reference<T>::type>(0)) >::value; }; template <typename T> struct is_container : has_iterator<T> {}; template <typename T> struct is_container<T[]> : std::true_type {}; template <typename T, std::size_t N> struct is_container<T[N]> : std::true_type {}; template <class... Args> struct is_container<std::vector<Args...>> : std::true_type {};` `

`for_each`实现很简单。 默认的函数会调用`function`

` ` template <typename Value, typename Function> typename std::enable_if<!is_container<Value>::value, void>::type rfor_each(const Value &value, Function function) { function(value); }` `

` ` template <typename Container, typename Function> typename std::enable_if<is_container<Container>::value, void>::type rfor_each(const Container &container, Function function) { for (const auto &i: container) rfor_each(i, function); }` `

` ` int main() { using namespace std; vector< vector< vector<int> > > A; A.resize(3, vector<vector<int> >(3, vector<int>(3, 5))); rfor_each(A, [](int i){ std::cout << i << ", "; }); // 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, std::cout << std::endl; double B[3][3] = { { 1. } }; rfor_each(B, [](double i){ std::cout << i << ", "; }); // 1, 0, 0, 0, 0, 0, 0, 0, 0, }` `

` `for (auto& k : A) for (auto& i : k) for (auto& current_A : i) do_something_on_A(current_A);` `

` `#include "stdio.h" #define FOR(i, from, to) for(int i = from; i < to; ++i) #define TRIPLE_FOR(i, j, k, i_from, i_to, j_from, j_to, k_from, k_to) FOR(i, i_from, i_to) FOR(j, j_from, j_to) FOR(k, k_from, k_to) int main() { TRIPLE_FOR(i, j, k, 0, 3, 0, 4, 0, 2) { printf("i: %d, j: %d, k: %d\n", i, j, k); } return 0; }` `

` `multi_index mi (10, 8, 5); // The pseudo-container whose iterators give {0,0,0}, {0,0,1}, ... for (auto i : mi) { // In here, use i[0], i[1] and i[2] to access the three index values. }` `

` `double B[3][3][3]; // ... set the values somehow double* begin = &B[0][0][0]; // get a pointer to the first element double* const end = &B[3][0][0]; // get a (const) pointer past the last element for (; end > begin; ++begin) { (*begin) *= 2.0; }` `

` `double do_something(double d) { return d * 2.0; } ... double B[3][3][3]; // ... set the values somehow double* begin = &B[0][0][0]; // get a pointer to the first element double* end = &B[3][0][0]; // get a pointer past the last element std::transform(begin, end, begin, do_something);` `

` `//This is roughly what we want for values template<class input_type, class func_type> void rfor_each(input_type&& input, func_type&& func) { func(input);} //This is roughly what we want for containers template<class input_type, class func_type> void rfor_each(input_type&& input, func_type&& func) { for(auto&& i : input) rfor_each(i, func);}` `

` `//Compiler knows to only use this if it can pass input to func template<class input_type, class func_type> auto rfor_each(input_type&& input, func_type&& func) ->decltype(func(input)) { return func(input);} //Otherwise, it always uses this one template<class input_type, class func_type> void rfor_each(input_type&& input, func_type&& func) { for(auto&& i : input) rfor_each(i, func);}` `

` `template<class input_type, class func_type> auto rfor_each(input_type&& input, func_type&& func, int) ->decltype(func(input)) { return func(input);} //passing the zero causes it to look for a function that takes an int //and only uses ... if it absolutely has to template<class input_type, class func_type> void rfor_each(input_type&& input, func_type&& func, ...) { for(auto&& i : input) rfor_each(i, func, 0);}` `

` `#include <iostream> int main() { std::cout << std::endl; double B[3][3] = { { 1.2 } }; rfor_each(B[1], [](double&v){v = 5;}); //iterate over doubles auto write = [](double (&i)[3]) //iterate over rows { std::cout << "{"; for(double d : i) std::cout << d << ", "; std::cout << "}\n"; }; rfor_each(B, write ); };` `

` `template<class container> struct container_unroller { container& c; container_unroller(container& c_) :c(c_) {} template<class lambda> void operator <=(lambda&& l) {rfor_each(c, l);} }; #define FOR_NESTED(type, index, container) container_unroller(container) <= [](type& index) //note that this can't handle functions, function pointers, raw arrays, or other complex bits int main() { double B[3][3] = { { 1.2 } }; FOR_NESTED(double, v, B) { std::cout << v << ", "; } }` `

` `double B[10][8][5]; int index = 0; while (index < (10 * 8 * 5)) { const int x = index % 10, y = (index / 10) % 10, z = index / 100; do_something_on_B(B[x][y][z]); ++index; }` `

` `template <typename F, typename T, int X, int Y, int Z> void iterate_all(T (&xyz)[X][Y][Z], F func) { const int limit = X * Y * Z; int index = 0; while (index < limit) { const int x = index % X, y = (index / X) % Y, z = index / (X * Y); func(xyz[x][y][z]); ++index; } }` `

` `template <typename F, typename T, int X, int Y, int Z> void iterate_all(T (&xyz)[X][Y][Z], F func) { for (auto &yz : xyz) { for (auto &z : yz) { for (auto &v : z) { func(v); } } } }` `

` `int main() { int A[10][8][5] = {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}}; int B[7][99][8] = {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}}; iterate_all(A, do_something_on_A); iterate_all(B, do_something_on_B); return 0; }` `

### 迈向更通用

` `template<typename F, typename A> typename std::enable_if< std::rank<A>::value == 1 >::type iterate_all(A &xyz, F func) { for (auto &v : xyz) { func(v); } }` `

` `template<typename F, typename A> typename std::enable_if< std::rank<A>::value != 1 >::type iterate_all(A &xyz, F func) { for (auto &v : xyz) { iterate_all(v, func); } }` `

### 使用`std::vector`

` `template <typename F, typename T, template<typename, typename> class V> void iterate_all(V<T, std::allocator<T>> &xyz, F func) { for (auto &v : xyz) { func(v); } }` `

` `template <typename F, typename T, template<typename, typename> class V> void iterate_all(V<V<T, std::allocator<T>>, std::allocator<V<T, std::allocator<T>>>> &xyz, F func) { for (auto &v : xyz) { iterate_all(v, func); } }` `

` `int main() { using V0 = std::vector< std::vector< std::vector<int> > >; using V1 = std::vector< std::vector< std::vector< std::vector< std::vector<int> > > > >; V0 A0 = {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}}; V1 A1 = {{{{{9, 8}, {7, 6}}, {{5, 4}, {3, 2}}}}}; iterate_all(A0, do_something_on_A); iterate_all(A1, do_something_on_A); return 0; }` `

` `doOn( structure A, operator o) { for (int k=0; k<A.size(); k++) { for (int i=0; i<A[k].size(); i++) { for (int j=0; j<A[k][i].size(); j++) { o.actOn(A[k][i][j]); } } } } doOn(a, function12) doOn(a, function13)` `

` `template<typename T> void do_something_on_A(std::vector<T> &vec) { for (auto& i : vec) { // can use a simple for loop in C++03 do_something_on_A(i); } } void do_something_on_A(int &val) { // this is where your `do_something_on_A` method goes }` `

` `template<typename T> void do_something_on_vec(std::vector<T> &vec, std::function &func) { for (auto& i : vec) { // can use a simple for loop in C++03 do_something_on_vec(i, func); } } template<typename T> void do_something_on_vec(T &val, std::function &func) { func(val); }` `

` `do_something_on_vec(A, std::function(do_something_on_A));` `

` `int A = 4, B = 3, C = 3; for(int i=0; i<A*B*C; ++i) { int a = i/(B*C); int b = (i-((B*C)*(i/(B*C))))/C; int c = i%C; }` `

` `vector< vector< vector<int> > > A; int i,j,k; for(k=0;k<A.size();k++) for(i=0;i<A[k].size();i++) for(j=0;j<A[k][i].size();j++) { do_something_on_A(A[k][i][j]); }` `

` `double B[10][8][5]; int i,j,k; for(k=0;k<10;k++) for(i=0;i<8;i++) for(j=0;j<5;j++) { do_something_on_B(B[k][i][j]); }` `

` `#define FOR3(a,b,c,d,e,f,g,h,i) for(a;b;c) for(d;e;f) for(g;h;i)` `

` `double B[10][8][5]; int i,j,k; FOR3(k=0,k<10,k++,i=0,i<8,i++,j=0,j<5,j++) { do_something_on_B(B[k][i][j]); }` `

` `vector< vector< vector<int> > > A; int i,j,k; FOR3(k=0,k<A.size(),k++,i=0,i<A[k].size(),i++,j=0,j<A[k][i].size(),j++) { do_something_on_A(A[k][i][j]); }` `

` `#include <utility> #include <iterator>` `

` `template<typename C, typename F> void for_each_flat( C&& c, F&& f );` `

` `template<typename C, typename F> void for_each_flat_helper( C&& c, F&& f, std::true_type /*is_iterable*/ ) { for( auto&& x : std::forward<C>(c) ) for_each_flat(std::forward<decltype(x)>(x), f); } template<typename D, typename F> void for_each_flat_helper( D&& data, F&& f, std::false_type /*is_iterable*/ ) { std::forward<F>(f)(std::forward<D>(data)); }` `

` `namespace adl_aux { using std::begin; using std::end; template<typename C> decltype( begin( std::declval<C>() ) ) adl_begin(C&&); template<typename C> decltype( end( std::declval<C>() ) ) adl_end(C&&); } using adl_aux::adl_begin; using adl_aux::adl_end;` `

`TypeSink`用于testing代码是否有效。 你做`TypeSink< decltype(` code `) >` ，如果`code`是有效的，expression式是`void` 。 如果代码无效，SFINAE将会启动并阻止专业化：

` `template<typename> struct type_sink {typedef void type;}; template<typename T> using TypeSink = typename type_sink<T>::type; template<typename T, typename=void> struct is_iterable:std::false_type{}; template<typename T> struct is_iterable<T, TypeSink< decltype( adl_begin( std::declval<T>() ) ) >>:std::true_type{};` `

`for_each_flat`的最终实现最终变得非常简单：

` `template<typename C, typename F> void for_each_flat( C&& c, F&& f ) { for_each_flat_helper( std::forward<C>(c), std::forward<F>(f), is_iterable<C>() ); }` `

` `using std::array; array<array<array<double, 5>, 8>, 10> B; for (int k=0; k<10; k++) for (int i=0; i<8; i++) for (int j=0; j<5; j++) do_something_on_B(B[k][i][j]); // or, if you really don't like that, at least do this: for (int k=0; k<10; k++) { for (int i=0; i<8; i++) { for (int j=0; j<5; j++) { do_something_on_B(B[k][i][j]); } } }` `

` `#include <stdexcept> #include <array> using std::size_t; template <size_t M, size_t N, size_t P> class matrix3d { static_assert(M > 0 && N > 0 && P > 0, "Dimensions must be greater than 0."); std::array<std::array<std::array<double, P>, N>, M> contents; public: double& at(size_t i, size_t j, size_t k) { if (i >= M || j >= N || k >= P) throw out_of_range("Index out of range."); return contents[i][j][k]; } double& operator(size_t i, size_t j, size_t k) { return contents[i][j][k]; } }; int main() { matrix3d<10, 8, 5> B; for (int k=0; k<10; k++) for (int i=0; i<8; i++) for (int j=0; j<5; j++) do_something_on_B(B(i,j,k)); return 0; }` `