I have the struct and a template as below:
template <const int nrow, const int ncol>
struct Mat{
const int row_size = nrow;
const int col_size = ncol;
std::array<std::array<float, ncol>, nrow> mat;
};
I want to sort the matrix produced by Mat
struct, so I did:
int main(int argc, const char * argv[]) {
Mat<3, 3> mat;
mat.mat = {{{1,2,3},{4,5,6},{7,8,9}}};
std::sort(std::begin(mat.mat), std::end(mat.mat),
[](std::array<float, mat.col_size>& c1, std::array<float, mat.col_size>& c2){return c1[0]>c2[0];});
}
However, I get this error:
Non-type template argument is not a constant expression
and this expression,mat.col_size
, in sort is underlined red in XCode.
In the struct I made the col_size
a constant but it did not help. However, if I add static
keyword before it, then it works fine.
Why was there this error and what static
does?
You declared
row_size
andcol_size
as non-static data members, so although they areconst
, they can still be initialized to any value in any given instance of the class. The default member initializer is used only if no other value is given e.g. in an aggregate initialization.However you are trying to use these values as template arguments (e.g. in
std::array<float, mat.col_size>
), which must be known at compile-time. More specifically the template argument must be a "constant expression", so the members must be "usable in constant expressions". So they can't be object-dependent, at least as long as the class object itself is not a compile-time constant, aka "usable in constant expressions" by being declaredconstexpr
, and must be static:For
const int
with initializer this is sufficient for their values to be considered compile-time constants (aka. "usable in constant expressions"). For non-integral/enumeration types, you will need to replaceconst
withconstexpr
. (Integral and enumeration types are an exception not requiringconstexpr
for historical reasons.)