Невозможно построить массив constexpr из списка braced-init-list
Я реализовал массив constexpr
следующим образом:
template <typename T>
class const_array {
const T* p;
unsigned n;
public:
template <unsigned N>
constexpr const_array(const T(&a)[N]): p(a), n(N) { }
constexpr unsigned size() const { return n; }
};
int main(int argc, char* argv[]) {
// works
static_assert(const_array<double>{{1.,2.,3.}}.size() == 3);
// doesn't compile
constexpr const_array<double> a{{1.,2.,3.}};
static_assert(a.size() == 3);
}
Почему первая компиляция static_assert
, но инициализация a
терпит неудачу? Я использую gcc 6.2.0. Я получаю
: In function 'int main(int, char**)':
: error: 'const_array<double>{((const double*)(&<anonymous>)), 3u}' is not a constant expression
constexpr const_array<double> a{{1.,2.,3.}};
^
test/const_array.cc:17:3: error: non-constant condition for static assertion
static_assert(a.size() == 3);
^~~~~~~~~~~~~
Ответы
Ответ 1
Компилятор жалуется, что инициализатор a.p
не является постоянным выражением. Это не соответствует §5.20/5.2:
если значение имеет тип указателя, оно содержит адрес объекта со статической продолжительностью хранения, адрес после конца такого объекта (5.7), адрес функции или значение нулевого указателя
Другими словами, только значения указателя, известные компоновщику, являются действительными константами. (Кроме того, в вашем примере указатель свисает.)
Первый static_assert
не отключает это, потому что p
отбрасывается, а значение n
является постоянным выражением. Константные выражения могут иметь непостоянные подвыражения.
Это работает:
static constexpr double arr[] = { 1.,2.,3. };
constexpr const_array<double> a{ arr };
static_assert( a.size() == 3 );
Кредит @Jarod42 за то, что он указал на проблему в комментариях.
Ответ 2
Проблема заключалась в том, что вы не можете наследовать постоянный характер указателя на T во внутреннем шаблоне через параметр внешнего шаблона T.
template <typename T> class const_array {
const T * p;
unsigned n;
public:
template <unsigned N>
constexpr const_array(const T(& a)[N]): p(a), n(N) { }
};
int main(int argc, char* argv[]) {
constexpr const_array<double> ca{(const double []) { 1., 2. }};
return 0;
}
Я попробовал несколько десятков перестановок, чтобы избавиться от приведения без успеха.