【问题标题】:foreach loop in 2D Arrays in C++C ++中二维数组中的foreach循环
【发布时间】:2013-05-06 17:18:31
【问题描述】:

我有一个 3x3 二维数组。我想触及它的所有元素。可能吗?我这样做:

int myArray[3][3];
for(int &i: myArray){
   //MY CODE HERE.
}

但是当我这样做时,我得到了错误:

error: C2440: 'initializing' : cannot convert from 'int [3]' to 'int &'

我还在 Qt 5.0 x64 上使用 MSVC++ 2012 编译器。 如果可以的话,如何获取每个元素的索引号?

【问题讨论】:

    标签: c++ foreach multidimensional-array


    【解决方案1】:

    如果您只想在一个循环中遍历所有元素,那么您可以执行以下操作 (C++11):

    #include <type_traits>
    #include <algorithm>
    #include <cstdint>
    #include <cstdlib>
    #include <cstdio>
    
    #if defined(__clang__)
    #   define UTILITY_COMPILER_CXX_CLANG
    #   define UTILITY_COMPILER_CXX_VERSION             __clang_major__
    #   define UTILITY_COMPILER_CXX_VERSION_MINOR       __clang_minor__
    #   define UTILITY_COMPILER_CXX_VERSION_PATCHLEVEL  __clang_patchlevel__
    #   if __clang_major__ < 3
    #     error unsuported clang version
    #   endif
    #elif defined(__GNUC__)
    #   define UTILITY_COMPILER_CXX_GCC
    #   define UTILITY_COMPILER_CXX_VERSION             __GNUC__
    #   define UTILITY_COMPILER_CXX_VERSION_MINOR       __GNUC_MINOR__
    #   define UTILITY_COMPILER_CXX_VERSION_PATCHLEVEL  __GNUC_PATCHLEVEL__
    #   if __GNUC__ < 4
    #     error unsuported gcc version
    #   endif
    #elif defined(_MSC_VER)
    #   define UTILITY_COMPILER_CXX_MSC
    #   define UTILITY_COMPILER_CXX_VERSION _MSC_VER
    #else
    #   error unknown compiler
    #endif
    
    #ifdef UTILITY_COMPILER_CXX_MSC
    #   if UTILITY_COMPILER_CXX_VERSION >= 1900
    #       define UTILITY_PLATFORM_FEATURE_CXX_STANDARD_CONSTEXPR
    #   endif
    #else
    #   if __cplusplus >= 201103L
    #       ifdef UTILITY_COMPILER_CXX_GCC // specific case for GCC 4.7.x and lower
    #           if UTILITY_COMPILER_CXX_VERSION >= 5 || \
                   UTILITY_COMPILER_CXX_VERSION == 4 && UTILITY_COMPILER_CXX_VERSION_MINOR >= 8
    #               define UTILITY_PLATFORM_FEATURE_CXX_STANDARD_CONSTEXPR
    #           endif
    #       else
    #           define UTILITY_PLATFORM_FEATURE_CXX_STANDARD_CONSTEXPR
    #       endif
    #   endif
    #endif
    
    #ifdef UTILITY_PLATFORM_FEATURE_CXX_STANDARD_CONSTEXPR
    #   define CONSTEXPR constexpr
    #else
    #   define CONSTEXPR
    #endif
    
    namespace utility
    {
        // bool identity / identities
    
        template <bool b>
        struct bool_identity
        {
            using type = bool;
            static CONSTEXPR const bool value = b;
        };
    
        template <bool b>
        CONSTEXPR const bool bool_identity<b>::value;
    
        // Unrolled breakable `for_each` for multidimensional arrays
    
        namespace detail
        {
            template<bool is_array>
            struct _for_each_unroll
            {
                template <typename Functor, typename T, std::size_t N>
                _for_each_unroll(_for_each_unroll * parent_, T (& arr)[N], Functor && f) :
                    parent(parent_), break_(false)
                {
                    invoke(arr, std::forward<Functor>(f));
                }
    
                template <typename Functor, typename T, std::size_t N>
                _for_each_unroll(_for_each_unroll * parent_, T (&& arr)[N], Functor && f) :
                    parent(parent_), break_(false)
                {
                    invoke(std::forward<T[N]>(arr), std::forward<Functor>(f));
                }
    
                template <std::size_t I = 0, typename Functor, typename T, std::size_t N>
                typename std::enable_if<I == N, void>::type
                    invoke(T (& arr)[N], Functor && f)
                {
                }
    
                template <std::size_t I = 0, typename Functor, typename T, std::size_t N>
                typename std::enable_if<I == N, void>::type
                    invoke(T (&& arr)[N], Functor && f)
                {
                }
    
                template <std::size_t I = 0, typename Functor, typename T, std::size_t N>
                typename std::enable_if<I < N, void>::type
                    invoke(T (& arr)[N], Functor && f)
                {
                    if (!break_) {
                        _for_each_unroll<std::is_array<T>::value> nested_for_each{ this, arr[I], std::forward<Functor>(f) };
                        if (!nested_for_each.break_) {
                            invoke<I + 1, Functor, T, N>(arr, std::forward<Functor>(f));
                        }
                        else if (parent) parent->break_ = true;
                    }
                }
    
                template <std::size_t I = 0, typename Functor, typename T, std::size_t N>
                typename std::enable_if<I < N, void>::type
                    invoke(T (&& arr)[N], Functor && f)
                {
                    if (!break_) {
                        _for_each_unroll<std::is_array<T>::value> nested_for_each{ this, std::forward<T>(arr[I]), std::forward<Functor>(f) };
                        if (!nested_for_each.break_) {
                            invoke<I + 1, Functor, T, N>(arr, std::forward<Functor>(f));
                        }
                        else if (parent) parent->break_ = true;
                    }
                }
    
                _for_each_unroll * parent;
                bool break_;
            };
    
            template <typename Functor, typename T, bool is_array>
            inline void _invoke_breakable(_for_each_unroll<is_array> & this_, const T & value, Functor && f, bool_identity<false> is_breakable)
            {
                f(value);
            };
    
            template <typename Functor, typename T, bool is_array>
            inline void _invoke_breakable(_for_each_unroll<is_array> & this_, const T & value, Functor && f, bool_identity<true> is_breakable)
            {
                if (!f(value)) {
                    this_.break_ = true;
                }
            };
    
            template <typename Functor, typename T, bool is_array>
            inline void _invoke_breakable(_for_each_unroll<is_array> & this_, T && value, Functor && f, bool_identity<false> is_breakable)
            {
                f(std::forward<T>(value));
            };
    
            template <typename Functor, typename T, bool is_array>
            inline void _invoke_breakable(_for_each_unroll<is_array> & this_, T && value, Functor && f, bool_identity<true> is_breakable)
            {
                if (!f(std::forward<T>(value))) {
                    this_.break_ = true;
                }
            };
    
            template<>
            struct _for_each_unroll<false>
            {
                template <typename Functor, typename T>
                _for_each_unroll(void * parent, const T & value, Functor && f) :
                    break_(false)
                {
                    _invoke_breakable(*this, value, std::forward<Functor>(f), bool_identity<!std::is_void<decltype(f(value))>::value>{});
                }
    
                template <typename Functor, typename T>
                _for_each_unroll(void * parent, T && value, Functor && f) :
                    break_(false)
                {
                    _invoke_breakable(*this, value, std::forward<Functor>(f), bool_identity<!std::is_void<decltype(f(std::forward<T>(value)))>::value>{});
                }
    
                bool break_;
            };
        }
    
        template <std::size_t I = 0, typename Functor, typename T, std::size_t N>
        inline typename std::enable_if<I == N, void>::type
            for_each_unroll(T (& arr)[N], Functor && f)
        {
        }
    
        template <std::size_t I = 0, typename Functor, typename T, std::size_t N>
        inline typename std::enable_if<I == N, void>::type
            for_each_unroll(T (&& arr)[N], Functor && f)
        {
        }
    
        template <std::size_t I = 0, typename Functor, typename T, std::size_t N>
        inline typename std::enable_if<I < N, void>::type
            for_each_unroll(T (& arr)[N], Functor && f)
        {
            detail::_for_each_unroll<std::is_array<T>::value> nested_for_each{ nullptr, arr[I], std::forward<Functor>(f) };
            if (!nested_for_each.break_) {
                for_each_unroll<I + 1, Functor, T, N>(arr, std::forward<Functor>(f));
            }
        }
    
        template <std::size_t I = 0, typename Functor, typename T, std::size_t N>
        inline typename std::enable_if<I < N, void>::type
            for_each_unroll(T (&& arr)[N], Functor && f)
        {
            detail::_for_each_unroll<std::is_array<T>::value> nested_for_each{ nullptr, std::forward<T>(arr[I]), std::forward<Functor>(f) };
            if (!nested_for_each.break_) {
                for_each_unroll<I + 1, Functor, T, N>(std::forward<T[N]>(arr), std::forward<Functor>(f));
            }
        }
    }
    
    int main()
    {
        int i = 0;
        int a[2][3][4] = { 0 };
        utility::for_each_unroll(a, [&](int & value) {
            value = i;
            i++;
        });
    
        for (auto & j0 : a) for (auto & j1 : j0) for (auto & j2 : j1) printf("%u ", j2);
            
        puts("\n");
        
        i = 0;
        int b[2][3][4] = { 0 };
        utility::for_each_unroll(b, [&](int & value) {
            value = i;
            i++;
            if (i >= 3) return false;
            return true;
        });
        
        for (auto & j0 : b) for (auto & j1 : j0) for (auto & j2 : j1) printf("%u ", j2);
    }
    
    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 
    
    0 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    

    https://godbolt.org/z/oEPf4GMsz

    【讨论】:

      【解决方案2】:

      在 C++ 中

      using namespace std;
      int main()
      {
          int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
          for (auto &i : a)
          {
              for (auto &j : i)
              {
                  cout << j << " ";
              }
              cout << endl;
          }
      }
      

      【讨论】:

      【解决方案3】:

      只需输入int* 而不是int&amp;

          int myArray[3][3];
      
      for(int* rows: myArray) // Iterating over rows
      {
          for(int* elem: rows)
          {
              // do some stuff
          }
      }
      

      【讨论】:

      • 这不会编译,也不会。 for ( : ) 不适用于 int*。
      【解决方案4】:

      只需使用auto 关键字

      int myArray[3][3];
      
      for(auto& rows: myArray) // Iterating over rows
      {
          for(auto& elem: rows)
          {
              // do some stuff
          }
      }
      

      【讨论】:

      • 不会把i 变成int* 吗?
      • @MohammadRezaHajianpour, auto 关键字是 C++11 的特性,是的(如基于范围的 for 循环)
      • @mwerschy,在这种情况下,rows 将被推导出为int (&amp;)[3]
      • 我在谈论你在编辑之前所做的事情;)虽然你当然是对的,它不会是int*
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-22
      • 2018-07-13
      • 2022-12-01
      • 1970-01-01
      • 2022-12-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多