将未知维度的矩阵传递给 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>
(如果数组维度 nc
和 nr
都在编译时固定);
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;
}
}
此函数假定来自包含(嵌套)容器的容器的 begin
和 end
迭代器(因此从 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_t
到 int
的演员表存在限制问题,但确实不可能制作足够大的演员。
编辑:将多维数组转换为 one-dimensional 平面数组时,也存在潜在的 buffering/alignment 问题。但是我不知道这是一个问题的地方没有常见的现代编译器+硬件。请务必了解您的目标平台。
以下代码可以用 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 风格编写
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>
(如果数组维度nc
和nr
都在编译时固定);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;
}
}
此函数假定来自包含(嵌套)容器的容器的 begin
和 end
迭代器(因此从 std::vector<float>
传递迭代器将是可诊断错误)。它适用于任何类型的元素(例如,在您的情况下不限于 float
),可以流式传输到 std::ostream
.
我假定 row-major 在上面排序。 column-major 排序的调整微不足道。
要在
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_t
到 int
的演员表存在限制问题,但确实不可能制作足够大的演员。
编辑:将多维数组转换为 one-dimensional 平面数组时,也存在潜在的 buffering/alignment 问题。但是我不知道这是一个问题的地方没有常见的现代编译器+硬件。请务必了解您的目标平台。