Ответ 1
7.1.5 Спецификатор constexpr
[dcl.constexpr] говорит:
Определение конструктора
constexpr
должно удовлетворять следующие требования:
- класс не должен иметь виртуальных базовых классов;
- для конструктора copy/move, установленного по умолчанию, класс не должен иметь изменяемый подобъект, являющийся вариантом-членом;
- каждый из типов параметров должен быть литеральным типом;
- его тело функции не должно быть функцией-try-block;
Кроме того, либо его функциональный орган должен быть = delete, либо он должен удовлетворяют следующим требованиям:
- либо его тело функции должно быть = default, либо составной оператор его функционального тела должен удовлетворять требованиям для функции-тела функции constexpr;
- каждый невариантный нестатический элемент данных и под-объект базового класса должны быть инициализированы (12.6.2);
- если класс является объединением, имеющим вариантные члены (9.5), то один из них должен быть инициализирован;
- если класс является объединенным классом, но не является объединением, для каждого из его анонимных членов объединения, имеющих вариантные члены, точно один из они должны быть инициализированы;
- для конструктора без делегирования, каждый конструктор, выбранный для инициализации нестатических элементов данных и под-объектов базового класса, должен быть конструктор constexpr;
- для конструктора делегирования, конструктор назначения должен быть конструктором constexpr.
В двух словах = default
является допустимым определением конструктора по умолчанию constexpr
, если выполняются другие требования выше.
Итак, как это работает с неинициализированными конструкциями?
Это не так.
Например:
constexpr seconds x1{};
Вышеописанное работает и инициализирует x1
до 0s
. Однако:
constexpr seconds x2;
error: default initialization of an object of const type 'const seconds'
(aka 'const duration<long long>') without a user-provided default
constructor
constexpr seconds x2;
^
{}
1 error generated.
Итак, чтобы создать построенный constexpr
constexpr
по умолчанию duration
, вы должны его инициализировать нулем. И реализация = default
позволяет инициализировать нуль с помощью {}
.
Полная рабочая демонстрация:
template <class Rep>
class my_duration
{
Rep rep_;
public:
constexpr my_duration() = default;
};
int
main()
{
constexpr my_duration<int> x{};
}
Интересная боковая панель
Я узнал что-то в написании этого ответа и хотел поделиться:
Я продолжал задаваться вопросом, почему следующее не работает:
using Rep = int;
class my_duration
{
Rep rep_;
public:
constexpr my_duration() = default;
};
int
main()
{
constexpr my_duration x{};
}
error: defaulted definition of default constructor is not constexpr
constexpr my_duration() = default;
^
Почему создание этого класса не-шаблоном прерывает конструктор по умолчанию constexpr
?!
Затем я попробовал это:
using Rep = int;
class my_duration
{
Rep rep_;
public:
my_duration() = default; // removed constexpr
};
int
main()
{
constexpr my_duration x{};
}
И компиляторы снова этого типа.
Если это еще не проблема CWG, вероятно, должно быть. Поведение кажется немного непоследовательным. И это, вероятно, только потому, что мы (вся индустрия) все еще узнаем о constexpr
.