Как std:: chrono:: duration:: duration() будет constexpr?

Конструктор по умолчанию std::chrono::duration определяется следующим образом:

constexpr duration() = default;

(Например, см. cppreference.com или источник libstdС++.)

Однако cppreference.com также говорит об этом о конструкторах constexpr:

Конструктор constexpr должен удовлетворять следующим требованиям:

...

каждый базовый класс, и каждый нестатический член должен быть инициализирован, либо в списке инициализации конструкторов, либо в инициализаторе член-бит. Кроме того, каждый задействованный конструктор должен быть конструктором constexpr, и каждое предложение каждого инициализатора с фигурной скобкой должно быть постоянным выражением

И в случае, если я запутался в конструкторах по умолчанию, cppreference.com, кажется, говорит, что конструкторы по умолчанию появились с = default aren ' t определяется иначе, чем неявные конструкторы по умолчанию.

Тем не менее, тип rep для (большей) продолжительности - это целочисленный тип. Таким образом, не следует, чтобы явный конструктор по умолчанию = default для duration был эквивалентен

constexpr duration() {}

который, конечно, оставил бы целочисленную переменную-член типа duration::rep неинициализированной? И, по сути, это не стандартное поведение duration, так что значения, построенные по умолчанию, не инициализированы? (Но я не могу найти ссылку, которая прямо говорит об этом.)

Итак, как может конструктор = default для duration быть constexpr, если он не инициализируется нестатической переменной-членом? Что мне не хватает?

Ответы

Ответ 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.