Является ли следующая программа 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 и его подобъектов охватывает функцию, так о чем она?
Программа плохо формируется потому что вы не инициализируете 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
,.
Обновить
Я подал сообщение об ошибке для этого и ответ включает в себя это утверждение:
[…] Проблема в том, что мы еще не реализовали подразумеваемое правило, согласно которому такую функцию нельзя вызывать в константном выражении.
Других решений пока нет …