2016-06-29 3 views
8

Ich versuche, ein bisschen mehr auf lernen, wie C++ konstanten Ausdrücke in der Praxis und erstellt die folgende Matrix-Klasse-Vorlage zu Veranschaulichungszwecken verwenden:Warum beschwert sich der Compiler darüber, dass es kein Constexpr ist?

#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_{}; 
}; 

Die Idee ist, eine einfache Matrix-Klasse zu haben, was ich kann Verwenden Sie diese Option für kleine Matrizen, um Matrix-Ausdrücke zum Zeitpunkt der Kompilierung auszuwerten (beachten Sie, dass ich noch nicht die üblichen Matrix-Operatoren für Addition und Multiplikation implementiert habe).

Wenn ich versuche, eine Matrix-Instanz zu initialisieren, wie folgt:

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

ich die folgende Fehlermeldung erhalten vom Compiler (MS Visual C++ 14):

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

Hinweis sicher, was ich bin falsch machen ... jede Hilfe, um diese Arbeit zu machen, würde sehr geschätzt werden!

+0

Vielleicht 'std :: array' keinen constexpr Copykonstruktor? –

+2

Entfernen Sie die Definition des Destruktors –

+2

Als Nebenbemerkung, es ist nicht notwendig, 'numrows_' und' numcols_' als Elementvariablen zu speichern. Da Sie die Werte bereits als Vorlagenparameter haben, geben Sie diese einfach zurück. –

Antwort

13

[basic.types]/p10 heißt:

A-Typ ist ein Typ literal wenn er:

  • möglicherweise cv-qualifizierte void; oder

  • ein skalarer Typ; oder

  • ein Referenztyp; oder

  • ein Array von Literaltyp; oder

  • eine ggf. cv qualifizierten Klassentyp (Klausel [class]), die alle der folgenden Eigenschaften hat:

    • es hat eine triviale destructor,

    • es ist entweder ein Verschluss ([expr.prim.lambda]), ein Aggregat-Typ ([dcl.init.aggr]), oder mindestens einen conexpr-Konstruktor oder eine Konstruktormaske (möglicherweise geerbt ([namespace.udecl]) von einer Basisklasse), die kein Kopie- oder Verschiebekonstruktor ist,

    • , wenn es sich um eine Vereinigung ist, zumindest einer seiner nicht-statische Datenelemente von nichtflüchtigen Literal-Typ ist, und

    • , wenn es nicht eine Vereinigung ist, alle seine nicht-statische Datenelemente und Basis Klassen sind nicht flüchtige Literaltypen.

wo [class.dtor]/p5 sagt, dass:

A destructor trivial ist, wenn sie nicht durch den Benutzer vorgesehen ist, und wenn:

(5.4) - der Destruktor nicht virtual,

(5,5) - alle direkten Basisklassen seiner Klasse triviale Destruktoren haben und

(5,6) - für alle der nicht- Statische Datenelemente seiner Klasse, die vom Klassentyp (oder Array davon) sind, jede dieser Klasse hat einen trivialen Destruktor.

Andernfalls ist der Destruktor nicht trivial.

Mit anderen Worten, eine constexpr Instanz von Matrix zu erklären, muss es ein wörtlicher Typ sein und eine wörtliche Art zu sein, muss sein destructor entweder default ed oder ganz entfernt, so:

~Matrix() = default; 

oder:


                
+0

Vielen Dank für alle Klarstellungen! – BigONotation

+6

Ich mag die _or_. :-) – skypjack