2016-06-29 17 views
8

Sto cercando di imparare un po 'di più su come utilizzare C++ espressioni costanti nella pratica e ha creato il seguente modello classe Matrix a scopo illustrativo:Perché il compilatore si lamenta di non essere un constexpr?

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

L'idea è quella di avere una semplice classe Matrix, che posso utilizzare per piccole matrici per valutare le espressioni Matrix al momento della compilazione (si noti che non ho ancora implementato i soliti operatori Matrix per l'addizione e la moltiplicazione).

Quando cerco di inizializzare un'istanza di matrice come segue:

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

sto ottenendo il seguente errore del compilatore (MS Visual C++ 14):

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

Nota sicuro di quello che sono fare male ... qualsiasi aiuto per fare questo lavoro sarebbe molto apprezzato!

+0

Forse 'std :: array' non ha un costruttore di copia constexpr? –

+2

Rimuovere la definizione del distruttore –

+2

Come sidenote, non è necessario memorizzare 'numrows_' e' numcols_' come variabili membro. Dato che hai già i valori come parametri del modello, restituiscili. –

risposta

13

[basic.types]/p10 precisa che:

Un tipo è un tipo letteralese è:

  • possibilmente cv qualificati void; oppure

  • un tipo scalare; oppure

  • un tipo di riferimento; oppure

  • un array di tipo letterale; o

  • un tipo eventualmente cv qualificato classe (clausola [class]) che ha tutte le seguenti proprietà:

    • ha un distruttore banale,

    • o è un tipo di chiusura ([expr.prim.lambda]), un tipo di aggregato ([dcl.init.aggr]) o almeno un modello di costruttore o costruttore constexpr (possibilmente ereditato ([namespace.udecl]) da una classe base) che non è un costruttore di copia o spostamento,

    • se è unione, almeno uno dei suoi membri di dati non statici è di tipo letterale non volatile, e

    • se non è un'unione, tutti i suoi membri di dati non statici e basamento le classi sono di tipo letterale non volatile.

dove [class.dtor]/p5 dice che:

un distruttore è banale se non è fornita dall'utente e se:

(5.4) - il distruttore non è virtual,

(5,5) - tutte le classi base dirette della sua classe hanno distruttori banali, e

(5,6) - per tutti i non- membri di dati statici della sua classe che sono di tipo di classe (o matrice di essi), ciascuna di queste classi ha un distruttore banale.

In caso contrario, il distruttore è non banale.

In altre parole, per dichiarare un'istanza constexpr di Matrix, deve essere un tipo letterale, ed essere un tipo letterale, il suo distruttore deve essere o default cato, o rimosso del tutto, così:

~Matrix() = default; 

o:

+0

Grazie mille per tutti i chiarimenti! – BigONotation

+6

Mi piace il _or_. :-) – skypjack