Why does the compiler complain that it is not constexpr?

I try to learn a little more about how to use C ++ constant expressions in practice, and created the following Matrix class template for illustrative purposes:

#include <array> template <typename T, int numrows, int numcols> class Matrix{ public: using value_type = T; constexpr Matrix() : {} ~Matrix(){} constexpr Matrix(const std::array<T, numrows*numcols>& a) : values_(a){} constexpr Matrix(const Matrix& other) : values_(other.values_){ } constexpr const T& operator()(int row, int col) const { return values_[row*numcols+col]; } T& operator()(int row, int col){ return values_[row*numcols+col]; } constexpr int rows() const { return numrows; } constexpr int columns() const { return numcols; } private: std::array<T, numrows*numcols> values_{}; }; 

The idea is to have a simple Matrix class that I can use for small matrices to evaluate Matrix expressions at compile time (note that I have not yet implemented the usual Matrix operators for addition and multiplication).

When I try to initialize a Matrix instance as follows:

 constexpr std::array<double, 4> a = {1,1,1,1}; constexpr Matrix<double, 2, 2> m(a); 

I get the following error from the compiler (MS Visual C ++ 14):

 error: C2127: 'm': illegal initialization of 'constexpr' entity with a non-constant expression 

Notice what I'm doing wrong ... any help to make this work will be greatly appreciated!

+8
c ++ c ++ 11 visual-c ++ constexpr
source share
1 answer

[basic.types] / p10 states that:

A type is a literal type if it:

  • possibly cv-qualified void ; or

  • scalar type; or

  • reference type; or

  • an array of type literal; or

  • possibly cv-qual type type (Clause [class] ), which has all of the following properties:

    • has a trivial destructor,

    • it is either a closure type ( [expr.prim.lambda] ), a cumulative type ( [dcl.init.aggr] ), or it has at least one constructor constructor or constexpr constructor (possibly inherited ( [namespace.udecl] ) from the base class) which is not a copy or move constructor,

    • if it is a union, at least one of its non-static data elements has a non-volatile literal type and

    • if it is not a union, all of its non-static data elements and base classes are non-volatile literals.

where [class.dtor] / p5 says that:

A destructor is trivial if it is not provided by the user, and if:

(5.4) - the destructor is not virtual ,

(5.5) - all direct base classes of its class have trivial destructors, and

(5.6) - for all non-static data members of its class that belong to the type of the class (or its array), each of these classes has a trivial destructor.

Otherwise, the destructor is not trivial.

In other words, in order to declare an instance of constexpr Matrix , it must be a literal type and be a literal type, its destructor must be either default ed or deleted completely, therefore:

 ~Matrix() = default; 

or

+13
source share

All Articles