As noted in comments, C++ does not support variable-length arrays (VLAs). C did from the 1999 standard, but that became optional in C11. In combination, those factors are relevant to why gcc (depending on version) accepts your code, but g++ does not.
In C (and C++ if writing in a C style <blech!>), an alternative is to pass a single-dimensional array (with contiguous elements) to a function that accepts a pointer and use an indexing scheme to access elements. For example, assuming row-major ordering;
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");
}
}
In C++, one can use - depending on which (if any) dimensions are known at compile time;
std::array<std::array<float, nc>, nr>
(if array dimensions nc
and nr
are both fixed at compile time);
std::vector<std::vector<float> >
(if neither dimension is known
until run time). Bear in mind that individual std::vector<float>
s
in a std::vector<std::vector<float> >
CAN have different dimensions. Your caller will need to ensure dimensions are the same for all contained std::vector<float>
s and/or your function will need to check sizes.
If nc
is fixed at compile time but nr
is not, you can use std::vector<std::array<float, nc> >
. If nr
is fixed at compile time, but nc
is not, you can use std::array<std::vector<float>, nr>
.
If you must pass the entire vector/array, usually better to pass it by reference than by value. For example;
void print_mat(const std::array<std::array<float, nc>, nr> &)
{
// definition
}
or (if you need to pass around some arrays of different dimensions) create a family of such functions
template<int nc, int nr>
void print_mat(const std::array<std::array<float, nc>, nr> &)
{
// definition
}
Personally, I would not actually pass arrays or vectors around. I'd use iterators, such as;
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;
}
}
This function assumes begin
and end
iterators from a container that contains (nested) containers (so passing iterators from a std::vector<float>
will be a diagnosable error). It works for any type of element (e.g. is not limited to float
in your case), that can be streamed to a std::ostream
.
I've assumed row-major ordering in the above. The adjustments for column-major ordering are trivial.