在 C++ 中将不同大小的常量数组作为函数参数传递

Posted

技术标签:

【中文标题】在 C++ 中将不同大小的常量数组作为函数参数传递【英文标题】:Passing constant Arrays with different sizes as function parameters in C++ 【发布时间】:2011-01-03 14:54:20 【问题描述】:

我有不同大小的恒定多维数组。我想将它们传递给一个函数。但是,我会得到错误缺少下标,数组的大小不同,所以我不能将下标放在数组参数中。这个问题的解决方法是什么?

这是一个示例代码。实际的数组更大。

//ARRAY1
const double ARRAY1[3][2][2] =

    
        1.0,1.0,
        1.0,1.0,
    
    ,
    
        1.0,1.0,
        1.0,1.0,
    
    ,
    
        1.0,1.0,
        1.0,1.0,
    

//ARRAY2
const double ARRAY2[2][2][2] =

    
        1.0,1.0,
        1.0,1.0,
    
    ,
    
        1.0,1.0,
        1.0,1.0,
    


//How to declare the parameter?
double SomeFunctionToWorkWithBothArrays(const double arr[][][])



【问题讨论】:

请选择一种语言而不是两种。 C 和 C++ 对这个问题的回答会非常不同。 【参考方案1】:

你可以使用模板。

template<size_t first, size_t second, size_t third> 
double SomeFunction(const double (&arr)[first][second][third]) 
    return first + second + third;

这个函数引用一个双精度的三维数组,其中所有维度在编译时都是已知的。如果不顾一切,实际上可以通过模板获取此引用。

【讨论】:

谢谢你们的帮助。我将为此使用模板。 @DeadMG :并不棘手,但这就是我写评论时想到的:P 不明白为什么这很棘手。这是模板的基本用法! 需要注意的一点是,每个版本的函数都会有自己的函数代码的隐式实例化。 @Martin York:一个解决方案是从模板包装器中调用一个非模板函数并将指针和三个数组大小作为函数参数提交......虽然我不知道如果多维数组的布局是由标准定义的!?如果不是,它将依赖于实现特定的行为。【参考方案2】:

使用std::vector 而不是数组。向量知道自己的大小,所以这没有问题。您可以将向量的向量用作多维数组。

【讨论】:

对于他显然不需要的动态大小来说,这是相当大的堆开销。 @DeadMG:是的,事实上我在这里回答了一个稍微不同的问题。但是,恕我直言,“使用向量”是一个很好的经验法则。 可以回答数组的向量(即 boost/std:: 数组),例如 vector&lt;array&lt;array&lt;double, 2&gt;, 2&gt;&gt; 实际上几乎没有任何开销,并且动态分配不要求使用任何“堆”。但是,在可能的情况下坚持静态分配确实是首选。 :)【参考方案3】:

您可以使用std::vector(其大小是可变的,不需要在类型中指定),也可以坚持静态分配并使用模板:

template <size_t X, size_t Y, size_t Z>
double SomeFunctionToWorkWithBothArrays(const double (&arr)[X][Y][Z])

   // A different version of this function will
   // exist for each combination of X, Y and Z.

(在此示例中,我假设所有三个维度都可能不同。)

还请注意,我通过引用传递数组;实际上,您不能按值传递数组,因为参数会折叠成指针,而且对于多维数组,这会有点复杂。

希望这会有所帮助。

【讨论】:

【参考方案4】:

您可以使用 boost::array 模板类和模板函数声明来处理这个问题。

编辑:只是添加一个例子:

template<typename T, std::size_t I, std::size_t J, std::size_t K>
void MyFunction(const std::array<std::array<std::array<T, K>, J>, I>& data)

    // do something here

你会用以下方式调用它:

std::array<std::array<std::array<T, 4>, 2>, 3> data; // which hopefully you have typedef'd somewhere to make the code more readable
MyFunction<double, 3, 2, 4>(data);

【讨论】:

【参考方案5】:

我知道解决这个问题的两种方法:

    使用 sentinel 值作为数组的最后一个条目,例如。 -1.0,-1.0。您总是只需要检查下一个主要维度中的第一个值 向函数添加附加参数,指定维度的大小,例如。 x、y、z 或 struct dim int x, y, z;

问候,

马丁。

【讨论】:

【参考方案6】:

如果只有第一个维度是可变的(所有数组的其他维度都相同),那么您仍然可以将数组传递给同一个函数,因为您可以将第一个数组维度留在一个函数参数。

double SomeFunctionToWorkWithBothArrays(const double arr[][2][2])



如果其他维度也可以改变,那么您将不得不使用不同的函数,可能是从单个模板创建的,如@DeadMG 的答案所示。

【讨论】:

是的,但您应该真正提到,使用这种方法您需要将第一个维度的大小作为参数传递。【参考方案7】:

当且仅当多维数组的排列由标准定义(对标准专家的问题),您可以执行以下操作:

在您的标题中:

double SomeFunctionToWorkWithBothArraysInt(double const *data, int x, int y, int z);

template <size_t X, size_t Y, size_t Z>
double SomeFunctionToWorkWithBothArrays(double const (&arr)[X][Y][Z]) 
  SomeFunctionToWorkWithBothArraysInt(&arr, X, Y, Z);

在您的 .cpp 文件中:

double SomeFunctionToWorkWithBothArraysInt(double const *data, int x, int y, int z) 
  double res = 0.0;
  for (int xp = 0; xp < x; xp++) 
    for (int yp = 0; yp < y; yp++) 
      for (int zp = 0; zp < z; zp++) 
        res += data[(zp * y + yp) * x + xp]; // !!!ATTENTION!!!: This may be wrong if the array arrangement is different!
        
      
  

  return res;

优点是你的“业务逻辑”不会随着模板函数的每次实例化而被实例化,也不会通过头文件暴露出来。

【讨论】:

多维数组的排列由标准定义的。唯一的问题是你的电话应该是:SomeFunctionToWorkWithBothArraysInt(&amp;arr[0][0][0], X, Y, Z)。地址的值将保持不变,但 type 现在将是“指向 const double 的指针”而不是“指向 double 的数组(大小 Z)的数组的指针(大小 Y)”或“指针到双倍数组(大小 Z)的数组(大小 Y)的数组(大小 X)”(我不记得这两个中的哪一个。)【参考方案8】:

在 C 语言中,只需将函数定义为

double func (size_t x, size_t y, size_t z, double arr[x][y][z])

这是可能的,因为 C(与 C++ 不同)具有可变长度数组。

【讨论】:

以上是关于在 C++ 中将不同大小的常量数组作为函数参数传递的主要内容,如果未能解决你的问题,请参考以下文章

我们如何在 C++ 中将二维数组/向量作为函数参数传递? [复制]

C++ 数组与字符串⁽²³⁾|函数与数组

如果我尝试在不同的公共类中将数组作为参数传递,为啥我的构造函数无法在 Java 中编译?

传递数组的C大小[重复]

在 C++ (Arduino) 中将带有参数的函数作为参数传递

将函数作为参数传递。 C++