简体   繁体   中英

Why does the compiler complain about this not being a constexpr?

I am trying to learn a bit more on how to use C++ constant expressions in practice and created the following Matrix class template for illustration 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, which 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 am getting the following error from the compiler (MS Visual C++ 14):

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

Note sure what I am doing wrong...any help to make this work would be greatly appreciated!

[basic.types]/p10 states that:

A type is a literal type if it is:

  • possibly cv-qualified void ; or

  • a scalar type; or

  • a reference type; or

  • an array of literal type; or

  • a possibly cv-qualified class type (Clause [class] ) that has all of the following properties:

    • it has a trivial destructor,

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

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

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

where [class.dtor]/p5 says that:

A destructor is trivial if it is not user-provided and if:

(5.4) — the destructor is not virtual ,

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

(5.6) — for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.

Otherwise, the destructor is non-trivial .

In other words, to declare a constexpr instance of Matrix , it must be a literal type, and to be a literal type, its destructor must be either default ed, or removed altogether, so:

~Matrix() = default;

or:


	                    		               
		               

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM