Подтвердить что ты не робот

Почему ** не ** объявлять функцию `constexpr`?

Любая функция, состоящая только из оператора return, может быть объявлена constexpr и, таким образом, позволит оцениваться во время компиляции, если все аргументы constexpr, и только функции constexpr вызывают в своем тело. Есть ли причина, почему бы не объявить такую ​​функцию constexpr?

Пример:

  constexpr int sum(int x, int y) { return x + y; }
  constexpr i = 10;
  static_assert(sum(i, 13) == 23, "sum correct");

Может ли кто-нибудь предоставить пример, в котором объявление функции constexpr причинил бы какой-либо вред?


Некоторые исходные мысли:

Даже если не должно быть веских оснований для объявления функции not constexpr Я мог предположить, что ключевое слово constexpr имеет переходная роль: его отсутствие в коде, которому не требуется время компиляции оценки позволят компиляторам, которые не реализуют время компиляции оценки еще предстоит скомпилировать этот код (но с надежным отказом от кода которые нуждаются в них, как это сделано, используя constexpr).

Но я не понимаю: если не должно быть веских оснований для когда-либо объявляя функцию не constexpr, почему не каждая функция в стандартной библиотеке объявлено constexpr? (Вы не можете спорить что это еще не сделано, потому что еще не было достаточного времени для сделайте это, потому что делать это для всех - это не проблема - вопреки решению для каждой отдельной функции, если сделать ее constexpr или нет). --- Я знаю, что N2976 намеренно не требует cstrs для многих стандартных типов библиотек, таких как как контейнеры, поскольку это было бы слишком ограничивающим возможным Реализации. Давайте исключаем их из аргумента и просто задаемся вопросом: как только тип стандартной библиотеки имеет constexpr cstr, почему каждая работающая на нем функция объявила constexpr?

В большинстве случаев вы также не можете утверждать, что вы можете не объявлять функцию constexpr просто потому, что вы не планируете использовать время компиляции: потому что если другие evtl. будут использовать ваш код, они могут увидеть такое использование, которое ты не. (Но предоставляется, конечно, для типов типов типов и т.д.)

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

(с "каждой функцией" я всегда имею в виду: каждая функция, соответствующая требования для constexpr, то есть определяются как одиночные return, принимает только аргументы типов с constexpr cstrs и вызывает только функции constexpr.)

Вопрос Почему std::forward отбрасывает constexpr -ness? является частным случаем этого.

4b9b3361

Ответ 1

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

Объявление функции в стандартной библиотеке как constexpr требует, чтобы ВСЕ реализации выполняли эти правила.

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

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

Ответ 2

Я думаю, что вы называете частичную оценку. Что вы касаетесь, так это то, что некоторые программы можно разделить на две части - часть, которая требует информации о времени исполнения, и часть, которая может быть выполнена без какой-либо информации о времени выполнения, и что теоретически вы можете просто полностью оценить часть программы который не нуждается в какой-либо информации о времени выполнения, прежде чем вы начнете запускать программу. Есть некоторые языки программирования, которые делают это. Например, язык программирования D содержит интерпретатор, встроенный в компилятор, который позволяет выполнять код во время компиляции при условии, что он отвечает определенным ограничениям.

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

Я считаю, что причиной текущей спецификации constexpr является просто ограничение сложности компиляторов. Случаи, которые он ограничил, достаточно просты в проверке. Там нет необходимости реализовывать циклы в компиляторе (что может вызвать целый ряд проблем, например, что произойдет, если вы получите бесконечный цикл внутри компилятора). Он также избегает компилятору, который, возможно, должен оценивать операторы, которые могут вызывать segfaults во время выполнения, например, после плохого указателя.

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

Подводя итог, нет никакой теоретической причины, по которой вы не могли бы частично оценивать программы на С++ во время компиляции. Фактически, люди делают это все время. Например, оптимизация компиляторов - это программы, которые стараются сделать это как можно больше. Метапрограммирование шаблонов - это один из примеров, когда программисты на C++ пытаются выполнить код внутри компилятора, и можно сделать некоторые замечательные вещи с шаблонами частично, потому что правила для шаблонов образуют функциональный язык, который у компилятора проще выполнять. Более того, если вы думаете о компромиссе между часами автора и часами программирования, метапрограммирование шаблонов показывает, что если вы в порядке, то программисты наклоняются назад, чтобы получить то, что они хотят, вы можете создать довольно слабый язык (систему шаблонов) и сохранить сложность языка проста. (Я говорю "слабый", как "не особенно выразительный", а не "слабый" в смысле теории вычислимости).

Надеюсь, это поможет!

Ответ 3

Если функция имеет побочные эффекты, вы не захотите ее отмечать constexpr. Пример

Я не могу получить никаких неожиданных результатов, на самом деле это выглядит как gcc 4.5.1 просто игнорирует constexpr