Почему немедленные функции не имеют значения noexcept по умолчанию и почему им разрешено быть noexcept (false)?

Начиная с C ++ 20, мы можем определять немедленные функции, используя спецификатор consteval. Когда функция объявляется consteval, каждый вызов этой функции должен создавать константу времени компиляции, в противном случае программа имеет неправильный формат. Кроме того, поскольку в C ++ 20 блоки try-catch разрешены в контекстах с постоянной оценкой, но создание исключений по-прежнему запрещено. Из-за этого я сначала подумал, что, поскольку consteval подразумевает inline, это также подразумевает noexcept, поскольку создание любого исключения запрещено. Как вы сейчас можете себе представить, это неверно: если вы не укажете noexcept, немедленная функция будет потенциально бросающей функцией со всеми вытекающими отсюда отрицательными сторонами. Есть ли причина для этого, о которой я не знаю?


person user7769147    schedule 23.05.2020    source источник
comment
со всеми вытекающими отсюда отрицательными сторонами Например?   -  person Nicol Bolas    schedule 23.05.2020
comment
@JesperJuhl: Вы не можете задать вопрос «почему?», Потому что в спецификации не указывается, почему какая-то конкретная функция такая, какая она есть. Вы не можете требовать цитат из спецификаций для того, что определяет спецификация.   -  person Nicol Bolas    schedule 23.05.2020
comment
некоторые алгоритмы выполняют разные действия в зависимости от спецификации noexcept (см. std :: vector :: resize ()). Также компилятор может удалить код обработки исключений для функции, не вызывающей выброса.   -  person user7769147    schedule 23.05.2020
comment
Я бы сказал, что это согласованность с обычной функцией, и, как вы сказали, выдача исключений по-прежнему запрещена, чтобы можно было изменить это более интуитивно.   -  person Jarod42    schedule 23.05.2020
comment
Почему должна consteval функция быть noexcept? Какие преимущества вы получили бы даже от такого нарушения ортогональности?   -  person Barry    schedule 23.05.2020
comment
@Barry Почему функция consteval должна быть noexcept? потому что она никогда не бросает   -  person user7769147    schedule 23.05.2020
comment
@ user7769147 Это правда, но тоже не дает ответа на вопрос.   -  person Barry    schedule 23.05.2020
comment
Еще в C ++ 11 constexpr подразумевал const для функций-членов. Посмотрите, чем это закончилось.   -  person T.C.    schedule 23.05.2020


Ответы (1)


Некоторые алгоритмы выполняют разные действия в зависимости от спецификации noexcept (см. Std :: vector :: resize ()). Также компилятор может удалить код обработки исключений для функции, не вызывающей выброса.

Непосредственные функции вызываются во время компиляции. Хотя в C ++ 20 действительно есть контейнеры времени компиляции, их производительность не имеет отношения к коду времени выполнения. И им было бы достаточно просто использовать различные внутренние реализации на основе if(is_constant_evaluated), что принесло бы больше, чем просто noexcept запросы.

Но даже в этом случае одна из целей кодирования constexpr - сделать код времени компиляции похожим на код времени выполнения. Итак, если у вас есть класс, который должен существовать только во время компиляции и имеет consteval конструктор перемещения, то пользователь должен думать о нем точно так же, как о классе времени выполнения. Поэтому, если они сделают конструктор перемещения noexcept в классе времени выполнения, он также должен быть в классе времени компиляции.

И это вдвойне важно, поскольку это сохраняет способность кода времени компиляции генерировать исключения в будущих версиях языка. Это возможно, в частности, если P0709: Статические исключения попадает в стандарт.

Кроме того, немедленные функции существуют только во время компиляции, а это контекст, в котором нет обработки исключений. Итак, что бы ни делал компилятор для создания кода для функции constexpr, он не задействует механизмы обработки исключений. Поэтому делать их неявно noexcept для целей генерации кода не имеет смысла.

Наконец, consteval в конечном итоге построен как незначительное изменение по сравнению с объявлениями функций constexpr. Даже неявное inline происходит от consteval, означающего constexpr, а не от самого consteval. Добавление новой семантики в consteval внесет значительные изменения.

person Nicol Bolas    schedule 23.05.2020
comment
он сохраняет способность кода времени компиляции генерировать исключения в будущем, эти исключения приведут к ошибке времени компиляции, в любом случае они не будут распространяться за пределы функций. немедленные функции всегда существуют только во время компиляции, что является контекстом, который не имеет обработки исключений, рассмотрите consteval int foo() {return 42; } void bar(int = foo()) noexcept; в этом случае bar () не noexcept! - person user7769147; 23.05.2020
comment
эти исключения приведут к ошибке времени компиляции, они все равно не будут распространяться из функций. Я говорю о будущем изменении языка, где они снимают запрет на создание исключений во время компиляции. - person Nicol Bolas; 23.05.2020
comment
@ user7769147: в данном случае bar () не noexcept! Да, это так. noexcept не проверяет, не может ли содержащийся в нем код вызвать исключение. Это просто заявление о том, что эта функция не будет генерировать исключения, и если она попытается это сделать, будет вызываться std::terminate. - person Nicol Bolas; 23.05.2020
comment
Я говорю о будущем изменении языка, где они снимают запрет на выдачу исключений во время компиляции это вообще не имеет никакого смысла, выброс исключения в контексте времени компиляции должен быть похож на при использовании static_assert компиляция должна останавливаться вместо обработки исключения во время выполнения. в этом случае bar () не является исключением! Да это ты прав мой плохой - person user7769147; 23.05.2020
comment
@ user7769147: генерирование исключения в контексте времени компиляции должно быть похоже на использование static_assert, компиляция должна останавливаться вместо обработки исключения во время выполнения. Я ничего не сказал об обработке исключения во время выполнения; исключение времени компиляции будет обрабатываться во время компиляции. Обработка исключений - это, по сути, механизм потока управления. Пока исключение времени компиляции не переходит в код времени выполнения, все в порядке. Это позволит consteval функциям выдавать ошибки, используя стандартные механизмы, вместо того, чтобы возвращать optional, который вы должны явно проверить. - person Nicol Bolas; 23.05.2020
comment
исключения времени компиляции в этом смысле уже существуют, if(condition) throw "...."; в немедленной функции остановит компиляцию тогда и только тогда, когда condition истинно - person user7769147; 23.05.2020
comment
@ user7769147: Когда я говорю об исключении времени компиляции, я не имею в виду, что компиляция останавливается, когда генерируется исключение. Я имею в виду, что распространение исключения происходит во время компиляции, как и все остальное в C ++, допустимое во время компиляции. - person Nicol Bolas; 23.05.2020
comment
Какова была бы цель всего этого? - person user7769147; 23.05.2020
comment
@ user7769147: Не каждое исключение означает, что мир сломан и приложение должно завершиться. Исключения могут быть восстанавливаемыми состояниями, а распространение исключений позволяет передавать эту информацию по назначению без использования большого количества промежуточного кода, проверяющего возвращаемое значение каждой функции. - person Nicol Bolas; 23.05.2020
comment
Это имеет смысл во время выполнения, я не вижу допустимого использования исключений во время компиляции - person user7769147; 24.05.2020