2016-06-29 7 views
8

Próbuję dowiedzieć się nieco więcej o tym, jak używać wyrażeń stałej C++ w praktyce i stworzył następujące klasy Matrix szablon dla celów ilustracji:Dlaczego kompilator narzeka, że ​​nie jest to 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_{}; 
}; 

Chodzi o to, aby mieć prostą klasę Matrix, które mogę użyj dla małych macierzy do oceny wyrażeń Matrix podczas kompilacji (pamiętaj, że nie zaimplementowałem zwykłych operatorów Matrix do dodawania i mnożenia).

Kiedy próbuję zainicjować instancji Matrix następująco:

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

otrzymuję następujący błąd z kompilatorem (MS Visual C++ 14):

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

Uwaga pewien, kim jestem robić źle ... każda pomoc, aby ta praca była bardzo ceniona!

+0

Może 'std :: array' nie posiada constexpr kopiowania konstruktora? –

+2

Usuń definicję destruktora –

+2

Jako sidenote, nie ma potrzeby przechowywania "numrows_" i "numcols_" jako zmiennych członkowskich. Ponieważ już masz wartości jako parametry szablonu, po prostu je zwróć. –

Odpowiedz

13

[basic.types]/p10 stwierdza:

typ jest dosłowny rodzaj jeśli jest to:

  • ewentualnie cv wykwalifikowany void; lub

  • typ skalarny; lub

  • typ odniesienia; lub

  • tablica typu literalnego; lub

  • typu może cv wykwalifikowany klasy (§ [class]), który ma wszystkie z następujących właściwości:

    • ma trywialne destructor

    • jest albo typu zamknięcie ([expr.prim.lambda]), typ zagregowany ([dcl.init.aggr]) lub ma co najmniej jeden konstruktor constexpr lub szablon konstruktora (ewentualnie odziedziczony ([namespace.udecl]) z klasy bazowej), który nie jest konstruktorem kopiowania ani przenoszenia,

    • jeśli jest to związek, co najmniej jeden z jego non-statycznych danych jest nieulotnej typu dosłownym i

    • jeśli nie jest to związek, wszystkie jej non-statycznych danych i bazy klasy są nieulotnymi literalnymi typami.

gdzie [class.dtor]/p5 mówi, że:

Destruktor jest trywialne, jeśli nie jest podana przez użytkownika oraz jeżeli:

(5.4) - destruktory nie virtual,

(5,5) - wszystkich grup zasadowych bezpośrednich tej klasy są trywialne destruktory i

(5,6) - wszystkie o braku statyczne elementy danych swojej klasy, które są typu klasy (lub ich tablica), każda taka klasa ma trywialny destruktor.

W przeciwnym razie destruktor jest nietrywialny.

Innymi słowy, aby zadeklarować wystąpienie constexpr z Matrix musi być typu dosłownym oraz być typu dosłownym jego destructor musi być default ED, lub całkowicie usunięte, to:

~Matrix() = default; 

czyli


                
+0

Wielkie dzięki za wyjaśnienia! – BigONotation

+6

Podoba mi się _or_. :-) – skypjack