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.

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

Для большей ясности:

  • здесь компиляция прошла успешно с использованием clang 3.7.1
  • здесь компиляция завершается ошибкой с использованием GCC 5.3.0

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


person skypjack    schedule 04.03.2016    source источник
comment
Хм, Clang 3.7.1 принимает этот код. Бьюсь об заклад, это ошибка GCC.   -  person George Hilliard    schedule 04.03.2016
comment
Да, для меня это больше похоже на ошибку в компиляторе GCC, но это также может быть ошибка в clang!! Я не уверен, что это правильный код, хотя мне он кажется нормальным. Языковой юрист поможет здесь. :-)   -  person skypjack    schedule 04.03.2016
comment
Я добавил местоположение, на которое жалуется компилятор, вместе с окончательной версией для будущих сотрудников Google (последний стабильный GCC на момент написания этой статьи).   -  person George Hilliard    schedule 04.03.2016
comment
@thirtythreeforty Спасибо, очень признателен. Это знак (по крайней мере, для меня), что вы находите вопрос интересным. Хороший.   -  person skypjack    schedule 04.03.2016
comment
Определенно да. На самом деле это довольно далеко заходит в определения языковых юристов грамматики С++. Надеюсь, мой ответ будет достаточно строгим для вас: P   -  person George Hilliard    schedule 04.03.2016
comment
@dyp Другие версии GCC действительно работают нормально. См. здесь в качестве примера, это код, используемый для другой вопрос, и он основан на та же идея.   -  person skypjack    schedule 04.03.2016
comment
@thirtythreeforty Нет, подождите, на самом деле этот код не компилируется даже в Интернете, но ошибка имеет большее значение. Там также написано main.cpp:6:8: note: definition of 'struct D' is not complete until the closing brace. Тем не менее я думаю, что это ошибка компилятора GCC.   -  person skypjack    schedule 04.03.2016


Ответы (1)


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

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

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

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

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

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

Теперь класс следует считать завершенным в спецификаторе noexcept в соответствии с §9.2.2 Стандарта (выделено жирным шрифтом):

Класс считается полностью определенным типом объекта (3.9) (или полным типом) в конце } спецификатора класса. В спецификации-члена класса класс считается завершенным в пределах тел функций, аргументов по умолчанию, объявлений-использования, представляющих наследующие конструкторы (12.9 ), спецификации-исключений и скобки-или-равно-инициализаторы для нестатических членов данных (включая такие вещи во вложенных классах ). В противном случае он считается неполным в своем собственном классе member-specification.

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

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

  • динамическая-спецификация-исключения

  • нет-спецификации

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

person George Hilliard    schedule 04.03.2016
comment
На момент написания этой статьи я не вижу билета GCC для этой конкретной проблемы. Может быть, вы могли бы подать один? - person George Hilliard; 04.03.2016
comment
Я думаю, что да! Вы можете вернуться к этому ответу или скопировать соответствующие биты (в основном вторую половину). - person George Hilliard; 04.03.2016
comment
Обновленный вопрос. Хороший намек. Спасибо. - person skypjack; 04.03.2016
comment
Я должен принять ваш ответ, но я хотел бы знать, действительно ли это ошибка или нет, прежде чем отметить ее (узнайте об этом из билета для компилятора GCC). Если это не так, вы все равно заслуживаете голосования, но для ясности потребуется новый ответ, в котором говорится, что это не ошибка. Верно? - person skypjack; 04.03.2016
comment
Если это не ошибка GCC, я заслуживаю отрицательного голоса;). Звучит здорово. - person George Hilliard; 04.03.2016
comment
Абсолютно - если это не ошибка, вы все равно заслуживаете голоса, потому что я полностью согласен с вашей интерпретацией стандарта! Тот факт, что сопровождающие GCC могут отклонить заявку, заявив, что это не ошибка, не убедит меня в том, что это не ошибка!! :-Д - person skypjack; 04.03.2016
comment
Все еще не подтверждено. Обычно требуется так много времени, чтобы подтвердить ошибку GCC? - person skypjack; 09.03.2016
comment
Без понятия. Я никогда не подавал ни одного, хотя я рекомендовал подать несколько на основе сообщений SO. - person George Hilliard; 09.03.2016