【问题标题】:How to determine whether the passed array is 1-D, 2-D, OR N-D array如何判断传入的数组是一维、二维还是N-D数组
【发布时间】:2012-08-15 14:57:41
【问题描述】:

我想写一个函数,它接受一个数组作为输入参数。 并且该函数应该打印数组的所有元素。

print_array(arr)
{
  //print all the elemnts of arr.
}

我不知道该怎么做。

我认为首先我们需要找出传递的数组是 1-D 还是 2-D 还是 3-D 等等...数组

因为,要打印以下元素:

                            1-D array, you need only 1 for loop.
                            2-D array, you need only 2 for loop.
                            3-D array, you need only 3 for loop.

但是,我不知道您将如何识别它的一维、二维或 N-D 数组。 请帮忙。

【问题讨论】:

  • 如何修改函数签名如下:print_array(type *array, int n_dimensions, int *dimensions)?
  • 我不能将维度作为函数中的参数。该函数将只接受数组的基地址作为其输入。并且由函数的开发人员来确定它是 1-D 还是 2-D 还是 3-D 数组......并且基于此,他必须打印它的所有元素。
  • @VikasChhipa:一旦数组转换为指针,就不可能恢复该信息。唯一的选择是将维度传递给函数,或者传递对数组的引用而不转换为指针,如 eq- 的答案。
  • gslice 是用 C++ 表示多维数组的标准方法。 cplusplus.com/reference/std/valarray/gslice

标签: c++ c multidimensional-array


【解决方案1】:

您实际上可以很容易地找出确切的维数,只需使用 C++11 的 std::rank 类型特征进行一次重载:

#include <type_traits>
#include <iostream>

template<class T, unsigned N>
void print_dimensions(T (&)[N]){
  static unsigned const dims = std::rank<T>::value + 1;
  std::cout << "It's a " << dims << "-D array, you need "
            << dims << " for-loops\n";
}

但是,您实际上根本不需要std::rank 来打印所有元素;这可以通过简单的重载轻松解决:

namespace print_array_detail{
template<class T>
void print(T const& v){ std::cout << v << " "; }
template<class T, unsigned N>
void print(T (&arr)[N]){
  for(unsigned i=0; i < N; ++i)
    print(arr[i]);
  std::cout << "\n";
}
}

template<class T, unsigned N>
void print_array(T (&arr)[N]){ print_array_detail::print(arr); }

Live example.

【讨论】:

  • 在 C++03 中,使用来自 Boost.TypeTraits 的 boost::rank
  • @ecatmur:或者自己写,甚至在 cppreference 上有一个示例实现。 :)
  • 所以函数 print_array 本身也必须被模板化?
  • @Gir:是的,否则你不能接受不同类型的数组。
  • @Xeo:谢谢伙计......它的工作。因为,我在模板方面很弱......我不明白 print_array(T (&arr)[N]) 的含义......但我会试着自己理解它:-)
【解决方案2】:

您可以通过模板和 C++ 中的重载来达到此目的。考虑

template<size_t X, size_t Y>
int sum_array_dimensions(int (&arr)[X][Y])
{
  // it's 2d
  return X + Y;
}

template<size_t X, size_t Y, size_t Z>
int sum_array_dimensions(int (&arr)[X][Y][Z])
{
  // it's 3d
  return X + Y + Z;
}

【讨论】:

    【解决方案3】:

    您可以在参数中编码维数,并传递一维数组

    #define N1 10
    #define N2 100
    void function(unsigned dimensions, int* array)
    { switch(dimension):
      { case 1:
          for (int i=0;i<N;i++)
          { ... array[i] ...
          }
          break;
        case 2:
          for (int i=0;i<N;i++)
          { for (int j=0;j<N;j++)
            { ... array[i*N+j] ...
            }
          }
          break;
        case 3:
          for (int i=0;i<N;i++)
          { for (int j=0;j<N;j++)
            { for (int k=0;k<N;k++)
              { ... array[i*N2+j*N+k] ...
              }
            }
          }
          break;
      }
    }
    

    如果 N 是 2 的幂,您可以使用 &lt;&lt; 左移 (x*2^n == x&lt;&lt;n)
    edit 扩展解决方案优化乘法

    // the array is 0-indexed
    void function(unsigned* dimensions, int* array)
    { //dimensions[0] = number of dimensions
      //dimensions[1 ... dimensions[0] ] the dimensions themselves
      for(int i=1,n=1;i<=dimensions[0];i++)
      { n*=dimensions[i]; }
      /* if the order in the array happens to be the wanted one */
      for(int i=1;i<=n;i++)
      { print( array[i] );
      }
      /* otherwise the dimensions are specified in the dimension array */
      for(int i=1;i<=n;i++)
      { int k=0;
        int temp=i;
        int base=1;       
        for(int j=1;j<=dimensions[0];j++)
        { k+=(temp%dimension[j])*base;
          base*=dimension[j];
          temp/=dimension[j];
        }
        print(array[k]);
      }   
      */
    

    【讨论】:

    • 如果维度顺序不是默认的,则需要嵌套循环。在编辑后的示例中,我用 for 在尺寸上替换了嵌套循环。 (我最初不想包含扩展示例,因为 OP 已经找到了令人满意的答案)
    【解决方案4】:

    正如其他人所说,将数组传递给函数时会丢失数组的大小(除非通过引用传递)。所以你可以这样做:

    /* this function does the work */
    template <typename T>
    void bar(T* arr, size_t n_dims, size_t* sizes)
    {
        std::cout << n_dims << " dimension(s)\n";
        for (size_t i = 0; i < n_dims; ++i)   // for each dimension
            for (size_t j = 0; j < sizes[i]; ++j) ; // for each element
    }
    
    /* These are helper overloads to call bar with correct arguments. */
    /* You'll need to provide one for each number of dimension you want to support */
    
    template<typename T, size_t N>
    void foo(T (&arr)[N])
    {
        size_t sizes[] = {N};
        bar(arr, 1, sizes);
    }
    
    template<typename T, size_t N, size_t M>
    void foo(T (&arr)[N][M])
    {
        size_t sizes[] = {N, M};
        bar(arr, 2, sizes);
    }
    
    template<typename T, size_t N, size_t M, size_t O>
    void foo(T (&arr)[N][M][O])
    {
        size_t sizes[] = {N, M, O};
        bar(arr, 3, sizes);
    }
    
    int main()
    {
        int arr1[42];
        int arr2[2][2];
        int arr3[2][3][4];
        foo(arr1);
        foo(arr2);
        foo(arr3);
    }
    

    Live example.

    【讨论】:

      【解决方案5】:

      你做不到。但是您可以编写 3 个具有相同名称和不同参数(不同数组类型)的不同函数,然后每个函数将处理它自己的数组。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-10-23
        • 1970-01-01
        • 2014-06-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-27
        • 1970-01-01
        相关资源
        最近更新 更多