C ++ 1y / C ++ 14: не допускается ли присваивание объекту вне его времени жизни в постоянном выражении?

Является ли следующая программа C ++ 14 / C ++ 1y плохо сформированной в соответствии с текущим проектом?

#include <cstddef>

template<typename T, size_t n>
struct literal_array
{
T data[n];
};

template<typename T, size_t n, size_t m>
constexpr literal_array<T, n+m> operator+(literal_array<T, n> a,
literal_array<T, m> b)
{
literal_array<T, n+m> x;

for (size_t i = 0; i < n; i++)
x.data[i] = a.data[i];

for (size_t i = 0; i < m; i++)
x.data[n+i] = b.data[i];

return x;
}

int main()
{
constexpr literal_array<int, 3> a = { 1, 2, 3 };
constexpr literal_array<int, 2> b = { 4, 5 };

constexpr auto c = a + b;
}

Ствол Clang (на момент написания) дает:

error: constexpr variable 'c' must be initialized by a constant expression
constexpr auto c = a + b;
^   ~~~~~
assignment to object outside its lifetime is not allowed in a constant expression
x.data[i] = a.data[i];
^
in call to 'operator+({{1, 2, 3}}, {{4, 5}})'
constexpr auto c = a + b;
^

Что значит «присвоение объекту вне его времени жизни»? Время жизни x и его подобъектов охватывает функцию, так о чем она?

16

Решение

Программа плохо формируется потому что вы не инициализируете x, если вы измените определение на:

literal_array<T, n+m> x = {{0}};

clang больше не жалуется и компилируется без ошибок. Другое решение было бы создать constexpr consrtuctors.

Мы можем найти это в проект стандарта раздел 7.1.5 Спецификатор constexpr параграф 3 который говорит:

Определение constexpr функция должна удовлетворять следующему
ограничения:

и включает в себя следующую маркировку:

его функция тела должен быть = delete, = defaultили
компаунд-заявление что не содержит

который содержит эту пулю (акцент мой):

определение переменной не литерального типа или статического или потока
срок хранения или для которого не выполняется инициализация.

и позже у нас есть следующий пример:

constexpr int uninit() {
int a; // error: variable is uninitialized
return a;
}

Жалоба на всю жизнь x не кажется основанным в проект стандарта. Насколько я могу судить, правильной причиной должно быть что-то вроде object is not initialized,

Соответствующая цитата из проекта стандарта на время жизни объекта будет раздел 3.8 Время жизни объекта параграф 1 который говорит:

продолжительность жизни объекта является свойством времени выполнения объекта.
говорят, что объект имеет нетривиальную инициализацию, если он принадлежит к классу
или агрегатный тип, и он или один из его членов инициализируется
конструктор, отличный от обычного конструктора по умолчанию. [ Замечания:
инициализация тривиальным конструктором копирования / перемещения нетривиальна
инициализация. — конечная нота ] Время жизни объекта типа T начинается
когда:

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

На случай, если я что-то упустил, я тоже проверил, используя станд :: is_trivial:

std::cout <<  std::boolalpha << std::is_trivial<literal_array<int, 3>>::value << std::endl ;

и результат, как и ожидалось в true,.

Обновить

Я подал сообщение об ошибке для этого и ответ включает в себя это утверждение:

[…] Проблема в том, что мы еще не реализовали подразумеваемое правило, согласно которому такую ​​функцию нельзя вызывать в константном выражении.

10

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]