noexcept поведение функций constexpr

Формулировка [expr.unary.noexcept] изменена в C ++ 17.


Ранее (n4140, 5.3.7 оператор noexcept [expr.unary.noexcept]), мой акцент:

  1. Результатом оператора noexcept будет false, если в потенциально оцениваемом контексте выражение будет содержать
    # P3 #

Теперь 1 (7.6.2.6 оператор noexcept [expr.unary .noexcept]):

  1. Результатом оператора noexcept является истина, если выражение не является потенциально бросающим ([except.spec]).

А затем в 14.5 Спецификации исключений [except.spec]:

  1. Если объявление функции не имеет спецификатора noexcept-спецификатора, объявление имеет потенциально генерирующую спецификацию исключения, если ...

но if list из 14.5 (3) не перечисляет constexpr, оставляя его как потенциально бросающий ...

1 ссылка на C ++ 17 n4659, добавленный LF в комментарии.


Тестовый код

constexpr int f(int i) { return i; }

std::cout << boolalpha << noexcept(f(7)) << std::endl;
int a = 7;
std::cout << boolalpha << noexcept(f(a)) << std::endl;

используется для печати (с gcc 8.3):

true
false

оба при компиляции с -std = c ++ 11 и -std = c ++ 2a


Однако теперь печатается тот же код (с gcc 9.2):

false
false

оба при компиляции с -std = c ++ 11 и -std = c ++ 2a


Между прочим, Clang очень согласован, начиная с 3.4.1 и работает с:

false
false

  • Как правильно поступать в соответствии с каждой спецификацией?
  • Произошло ли реальное изменение в спецификации? Если да, то в чем причина этого изменения?
  • Если в спецификации есть изменение, которое влияет или противоречит прошлому поведению, будет ли обычной практикой подчеркивать это изменение и его последствия? Если изменение не выделено, может ли оно означать, что это может быть недосмотр?
  • Если это действительно запланированное изменение, считалось ли это исправлением ошибки, которое должно вернуться к предыдущим версиям спецификации, правильно ли компиляторы согласовали новое поведение задним числом с C ++ 11?

Примечание: вычет noexcept функции constexpr влияет на этот трюк .


person Amir Kirsh    schedule 08.03.2020    source источник
comment
Новое правило в C ++ 17: timsong-cpp.github. io / cppwp / n4659 / except.spec # 6. Я помню, что есть проблема с удалением специального правила для постоянных выражений.   -  person L. F.    schedule 08.03.2020
comment
Я нашел это: stackoverflow.com/a/47538175/2085626, который также имеет соответствующее обсуждение в комментариях   -  person Amir Kirsh    schedule 17.03.2020
comment


Ответы (1)


Резюме

Каково правильное поведение для каждой спецификации?

true false до C ++ 17, false false с C ++ 17.

Произошло ли реальное изменение в спецификации? Если да, то в чем причина этого изменения?

да. См. Цитату из отчета об ошибке Clang ниже.

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

Да; да (но позже CWG нашла причину оправдать оплошность, поэтому она была сохранена как есть).

Если это действительно запланированное изменение, считалось ли это исправлением ошибки, которое должно вернуться к предыдущим версиям спецификации, правильно ли компиляторы согласовали новое поведение задним числом с C ++ 11?

Я не уверен. См. Цитату из отчета об ошибке Clang ниже.

Деталь

Я искал много мест, и пока что самое близкое, что я могу найти, это комментарии к соответствующим отчетам об ошибках:

  • # P10 #
    # P11 #
    constexpr void f() {} static_assert(noexcept(f()));
    
    # P12 # # P13 #
    constexpr void f() {} static_assert(!noexcept(f()));
    
    # P14 #
  • Clang Bug 15481 - noexcept должен проверять, является ли выражение константным выражением

    Особый случай константных выражений был удален - по-видимому, случайно - wg21.link/p0003. Я выясняю, исчезнет ли он.

    Делали ли вы что-нибудь, чтобы избежать квадратичного времени выполнения глубоко вложенных выражений?

    [...]

    Вывод из обсуждения CWG: мы собираемся оставить это как есть. noexcept не имеет специального правила для постоянных выражений.

    Оказывается, это действительно важно для правильной работы библиотеки: например, если noexcept пытается оценить свой операнд, то (например) is_nothrow_swappable нарушается, создавая std::swap constexpr, потому что тогда std::swap<T> часто заканчивается тем, что создается экземпляр до завершения T.

    В результате я также собираюсь рассматривать это изменение как эффективное средство аварийного восстановления против C ++ 11 и C ++ 14 ... но я готов пересмотреть, если мы увидим много жалоб пользователей.

Другими словами, специальное правило было случайно удалено P0003, но CWG решила сохранить удаление.

person L. F.    schedule 08.03.2020