noexcept, наследование конструкторов и недопустимое использование неполного типа, который фактически завершен

Я не уверен, что это ошибка GCC компилятор или предполагаемое поведение noexcept.
Рассмотрим следующий пример:

struct B {
    B(int) noexcept { }
    virtual void f() = 0;
};

struct D: public B {
    using B::B;
    D() noexcept(noexcept(D{42})): B{42} { }
    void f() override { }
};

int main() {
    B *b = new D{};
}

если noexcept удаляется, компилируется.
Во всяком случае, как и в примере, я получил эту ошибку от GCC v5.3.1:

test.cpp:8:31: error: invalid use of incomplete type ‘struct D’
     D() noexcept(noexcept(D{42})): B{42} { }
                               ^

насколько я знаю, struct D не является неполным типом, но наследующие конструкторы участвуют в инструкции, и похоже, что компилятор фактически рассматривает полнота базовой структуры B больше, чем D.

это предполагаемое поведение или это юридический код?

для ясности:

  • здесь компиляция успешно выполняется с помощью лязгом 3.7.1
  • здесь компиляция не выполняется с помощью GCC 5.3.0

посмотреть этой ссылке до ошибка для компилятора GCC за дополнительной информацией.
В настоящее время ошибка все еще не подтверждена. Я уточню вопрос как можно скорее.

1 ответов


ваш код является законным, хотя GCC утверждает обратное. Он обижается на это забавное заявление:--7-->

D() noexcept(noexcept(D{42}));

внешний noexcept это как noexcept описатель, указав, что D::D() является noexcept тогда и только тогда, когда его аргумент константного выражения равен true. Внутреннее noexcept это оператор noexcept это проверяет во время компиляции, не вызывает ли его выражение аргумента, которое фактически не оценивается, никаких исключений. Потому что D::D(int) является noexcept (наследуется от B), это должно быть верно.

cppreference.com явно отмечает, что использование оператора внутри спецификатора разрешено (курсив добавлен):

оператор noexcept выполняет проверку времени компиляции, которая возвращает true, если выражение объявлено, чтобы не создавать никаких исключений.

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

теперь, класс должен быть рассмотрен полное в спецификаторе noexcept из-за §9.2.2 стандарта (выделено жирным шрифтом):

класс считается полностью определенным типом объекта (3.9) (или полным типом) при закрытии } на класс-описатель. в классе член-спецификация, класс считается полным в тела функций, аргументы по умолчанию, С помощью декларацииs введение наследующих конструкторов (12.9),исключение-спецификацияs и brace-or-equal-initializers для нестатических членов данных (включая такие вещи во вложенных классах). В противном случае он рассматривается как неполная в своем классе член-спецификация.

§15.4.1 определяет исключение-спецификация как следующая грамматика:

исключение-спецификация:

  • dynamic-exception-specification

  • как noexcept-спецификация

поэтому GCC не должен отклонять ваш код.