2016-06-29 2 views
8

Я пытаюсь узнать немного больше о том, как использовать постоянные выражения C++ на практике и создал следующий шаблон класса Matrix для целей иллюстрации:Почему компилятор жалуется, что это не является 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_{}; 
}; 

Идея заключается в том, чтобы иметь простой класс Matrix, который я могу использовать для малых матриц для оценки выражений Matrix во время компиляции (обратите внимание, что я еще не реализовал обычные матричные операторы для сложения и умножения).

При попытке инициализировать экземпляр матрицы следующим образом:

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

Я получаю следующее сообщение об ошибке от компилятора (MS Visual C++ 14):

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

Примечание уверен, что я делать не так ... любая помощь, чтобы сделать эту работу будет очень признательна!

+0

Может быть 'станд :: array' не имеет constexpr конструктор копирования? –

+2

Удалить определение деструктора –

+2

В качестве побочного элемента нет необходимости хранить 'numrows_' и' numcols_' в качестве переменных-членов. Поскольку у вас уже есть значения в качестве параметров шаблона, просто верните их. –

ответ

13

[basic.types]/p10 утверждает, что:

тип является буквальным типа если:

  • , возможно, резюме квалифицированных void; или

  • скалярный тип; или

  • ссылочный тип; или

  • массив литерального типа; или

  • типа, возможно, резюме квалифицированных класса (пункт [class]), который имеет все из следующих свойств:

    • имеет тривиальный деструктор,

    • это либо тип закрытия ([expr.prim.lambda]), совокупный тип ([dcl.init.aggr]) или имеет хотя бы один конструктор конструктора или конструктора constexpr (возможно, унаследованный ([namespace.udecl]) из базового класса), который не является конструктором копирования или перемещения,

    • , если оно является объединением, по меньшей мере, один из его нестатических элементов данных имеет энергонезависимую буквального типа, а

    • , если он не является объединением, все его нестатических членов данных и базы классы являются нелетучими литеральными типами.

где [class.dtor]/p5 говорит, что:

Деструктор тривиален, если он не является пользователем при условии, если:

(5.4) - деструктор не virtual,

(5,5) - все прямые базовые классы своего класса имеют тривиальные деструкторов и

(5,6) - для всех из не- статические члены данных своего класса, которые относятся к типу класса (или его массиву), каждый такой класс имеет тривиальный деструктор.

В противном случае деструктор нетривиальный.

Другими словами, чтобы объявить constexpr экземпляр Matrix, он должен быть буквальным тип, и быть буквальным типа, его деструктор должен быть либо default-е изд или удалены полностью, так что:

~Matrix() = default; 

или:


                
+0

Большое спасибо за все разъяснения! – BigONotation

+6

Мне нравится _or_. :-) – skypjack