Разрешено ли компилятору вызывать немедленную (consteval) функцию во время выполнения? - PullRequest
4 голосов
/ 19 октября 2019

Это может быть глупый вопрос, но я в замешательстве. У меня было ощущение, что немедленная (consteval) функция имеет для выполнения во время компиляции, и мы просто не можем увидеть ее тело в двоичном виде.

Эта статья явно поддерживает мои чувства:

Это означает, что [немедленная] функция видна только во время компиляции. Символы не выводятся для функции, вы не можете взять адрес такой функции, и такие инструменты, как отладчики, не смогут их отобразить. В этом случае непосредственные функции похожи на макросы.

Подобное сильное утверждение можно найти в публикации Херба Саттера :

Обратите внимание, что черновикC ++ 20 уже содержит часть первого раунда работы, связанной с отражением, для включения в стандарт: функции consteval , которые гарантированно будут выполняться во время компиляции , которые получены из работы отражения и предназначены специально дляиспользоваться для манипулирования информацией об отражениях.

Однако существует ряд свидетельств, которые не столь ясны в отношении этого факта.

Из cppreference :

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

Это не означает, что это имеет для вызова только во время компиляции.

с предложение P1073R3 :

В настоящее время существует общее согласие, что будущие языкиДля поддержки отражения следует использовать функции constexpr, но поскольку «функции отражения» обычно имеют , которые должны оцениваться во время компиляции, они, скорее всего, будут непосредственными функциями.

Похоже, это такозначает то, что я думаю, но все же это не ясно сказано. Из того же предложения:

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

Опять же, это не означает, что функция должна оцениваться только во время компиляции.

С этот ответ :

Ваш код должен создавать константу времени компиляции. Но выражение константы времени компиляции не является наблюдаемым свойством в контексте, где вы его использовали, и нет никаких побочных эффектов при выполнении этого по ссылке или даже во время выполнения ! И, как-будто ничто не мешает этому

Наконец, есть демонстрационная версия , где функция consteval явно вызывается во время выполнения. Тем не менее, я надеюсь, что это связано с тем, что consteval еще не поддерживается должным образом в clang и поведение на самом деле некорректно, как и в Почему функция conteval допускает неопределенное поведение?

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

  1. Непосредственная функция видна только во время компиляции (и не может быть оценена во время выполнения)
  2. Символы не выдаются для немедленной функции
  3. Такие инструменты, как отладчики, не смогут отображать немедленную функцию

Ответы [ 2 ]

5 голосов
/ 19 октября 2019

В предложении упоминается:

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

Так что это определенно намерение предложения о том, что вызовы заменяются константой. Другими словами, это константное выражение вычисляется во время перевода.

Однако, это не говорит о том, что требуется, чтобы оно не было замечено бэкэндом. Фактически, в другом предложении предложения просто говорится, что это маловероятно:

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


В более общем смысле, мы можем переформулировать вопрос следующим образом:

Вынуждают ли компиляторы вычислять константные выражения (везде; не только тогда, когда они определенно нужны?)это)?

Например, компилятору необходимо вычислить константное выражение, если это число элементов массива, поскольку ему необходимо статически определить общий размер массива.

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

Еще один интересный случай, о котором стоит подумать, этоинтерпретатор: хотя интерпретатору все еще нужно оценивать некоторые константные выражения, он может просто делать это все время лениво, не выполняя какое-либо постоянное свертывание.

Итак, насколько я знаю, они не требуются, но я не знаю точных цитат, которые нам нужны из стандарта, чтобы доказать это (или иначе). Возможно, это хороший дополнительный вопрос сам по себе, который также ответил бы на него.

Например, в [expr.const] p1 есть примечание, в котором говорится, что они могут, не то чтобы они были:

[Примечание: постоянные выражения могут быть оценены во время перевода. - конец примечания]

3 голосов
/ 19 октября 2019

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

  1. Непосредственная функция видна только во время компиляции (и не можетоценивается во время выполнения)
  2. Символы не выдаются для немедленной функции
  3. Инструменты, такие как отладчики, не смогут отображать немедленную функцию

Почти ни один из них не является ответом, который может дать стандарт C ++. Стандарт не определяет «символы» или то, что инструменты могут показать. Что касается стандарта, то почти все они являются выбором дилера.

Действительно, даже вопрос «время компиляции» и «время выполнения» - это то, с чем стандарт не имеет дела. Единственный вопрос, касающийся стандарта, заключается в том, является ли что-то постоянным выражением. Вызов функции constexpr может создать постоянное выражение в зависимости от его параметров. Вызов функции consteval способом, который не производит константное выражение, имеет форму il.

Тот, который стандарт определяет , определяет то, что "видно". Хотя дело не в «времени компиляции». В текущем проекте C ++ 20 есть ряд операторов, которые запрещают большинству функций иметь дело с указателями / ссылками на непосредственные функции. Например, N4835 (самый последний рабочий проект C ++ 20) в [expr.prim.id] / 3:

Идентификационное выражение, обозначающее непосредственную функцию, должно появляться только

  • как подвыражение немедленного вызова или

  • в контексте немедленной функции.

Так что, если вы не используете непосредственную функцию или не используете имя непосредственной функции для вызова другой непосредственной функции (передавая указатель / ссылку на функцию), то вы не можете назвать непосредственную функцию. И вы не можете получить указатель / ссылку на функцию, не назвав ее.

Этот и другие операторы в спецификации (например, указывает на непосредственную функцию, не являющуюся действительным результатом константных выражений )по сути, делает невозможным утечку указателя / ссылки на непосредственную функцию за пределы константных выражений.

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

И это в основном вещьс consteval. Он не использует стандартный язык для обеспечения того, что должно произойти. Он использует стандартный язык, чтобы сделать невозможным использование функции таким образом, чтобы предотвратил эти вещи. Поэтому разумнее сказать:

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

  2. Вы не можете использовать непосредственную функцию так, чтобы компилятор не отбрасывал символы для нее.

  3. Вы не можете использовать немедленную функцию таким образом, чтобы заставить отладчики иметь возможностьчтобы увидеть их.

Ожидается, что от этого зависит качество реализации.

Следует также отметить, что отладочные сборки предназначены для ... отладки. Для продвинутых инструментов компилятора было бы вполне разумно отлаживать код, который генерирует константные выражения. Таким образом, отладчик, который может видеть выполнение немедленных функций, является совершенно желательной технологией. Это становится тем более по мере того, как код времени компиляции становится все более сложным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...