将未知维度的矩阵传递给 C++ 函数

Pass matrix of unknown dimensions to C++ function

以下代码可以用 gcc 编译,但不能用 g++ 编译。是否可以在 C++ 中编写具有任意维度矩阵参数的函数?

void print_mat(const int nr, const int nc, const float x[nr][nc]);
#include <stdio.h>

void print_mat(const int nr, const int nc, const float x[nr][nc])
{
    for (int ir=0; ir<nr; ir++) {
        for (int ic=0; ic<nc; ic++) {
            printf(" %f",x[ir][ic]);
        }
        printf("\n");
    }
}

如注释中所述,C++ 不支持 variable-length 数组 (VLA)。 C 从 1999 年的标准开始,但在 C11 中成为可选的。结合起来,这些因素与为什么 gcc(取决于版本)接受您的代码,但 g++ 不接受您的代码有关。

在 C(和 C++,如果以 C 风格编写 ),另一种方法是将 single-dimensional 数组(具有连续元素)传递给接受指针并使用索引的函数访问元素的方案。例如,假设 row-major 排序;

void print_mat(const int nr, const int nc, const float *x)
{
    for (int ir=0; ir<nr; ir++)
    {
        int row_start = ir * nc;
        for (int ic=0; ic<nc; ic++)
        {
            printf(" %f",x[row_start + ic]);
        }
        printf("\n");
    }
}

在 C++ 中,可以使用 - 取决于在编译时已知哪些(如果有)维度;

  • std::array<std::array<float, nc>, nr>(如果数组维度 ncnr 都在编译时固定);
  • std::vector<std::vector<float> >(如果两个维度都未知 直到 运行 时间)。请记住,个人 std::vector<float>s 在 std::vector<std::vector<float> > 中可以有不同的维度。您的调用者需要确保所有包含的 std::vector<float>s 的尺寸相同 and/or 您的函数将需要检查尺寸。

如果 nc 在编译时固定但 nr 不是,您可以使用 std::vector<std::array<float, nc> >。如果 nr 在编译时固定,但 nc 不是,则可以使用 std::array<std::vector<float>, nr>.

如果必须传递整个 vector/array,通常通过引用传递比通过值传递更好。例如;

void print_mat(const std::array<std::array<float, nc>, nr> &)
{
     // definition
}

或者(如果您需要传递一些不同维度的数组)创建一个这样的函数族

template<int nc, int nr>
void print_mat(const std::array<std::array<float, nc>, nr> &)
{
     // definition
}

就个人而言,我实际上不会四处传递数组或向量。我会使用迭代器,例如;

template<class NestedIterator>
void print_mat(NestedIterator row, NestedIterator end_row)
{
     while (row != end_row)
     {
           auto col = std::begin(*row);     // Assuming C++11 and later
           auto col_end = std::end(*row);
           while (col != col_end)
           {
               std::cout << ' ' << *col;
               ++col;
           }
           std::cout << '\n';   // or std::endl
           ++row;
     }
}

此函数假定来自包含(嵌套)容器的容器的 beginend 迭代器(因此从 std::vector<float> 传递迭代器将是可诊断错误)。它适用于任何类型的元素(例如,在您的情况下不限于 float),可以流式传输到 std::ostream.

我假定 row-major 在上面排序。 column-major 排序的调整微不足道。

要在 上构建,您可以使用具有适当索引的 single-dimension 变体来完成这项工作。但是你可以使调用函数在C++中更好:

void print_mat(const int nr, const int nc, const float *x)
{
  ...
}

template <std::size_t NumRows, std::size_t NumColumns>
void print_mat(const float (*x)[NumRows][NumColumns])
{
  print_mat((int)NumRows, (int)NumColumns, (const float *)x);
}

现在可以自然的使用函数了:

float matrix[4][3] = { ... };

print_mat( matrix );

但是,只要您不让数组降级为指针

,这才有效

此外,从 size_tint 的演员表存在限制问题,但确实不可能制作足够大的演员。

编辑:将多维数组转换为 one-dimensional 平面数组时,也存在潜在的 buffering/alignment 问题。但是我不知道这是一个问题的地方没有常见的现代编译器+硬件。请务必了解您的目标平台。