Связь между constexpr и чистыми функциями
Я прав, что:
- Любая функция, определенная с помощью
constexpr
, является чистой функцией и
- Любая чистая функция может быть и должна быть определена с помощью
constexpr
, если это не очень дорого для компилятора.
И если да, то почему arent <cmath>
функции, определенные с помощью constexpr
?
Ответы
Ответ 1
Чтобы добавить к сказанному, рассмотрим следующий шаблон функции constexpr
:
template <typename T>
constexpr T add(T x, T y) { return x + y; }
Этот шаблон constexpr
можно использовать в константном выражении в некоторых случаях (например, где T
есть int
), но не в других (например, где T
- тип класса с operator+
перегрузка, которая не объявлена constexpr
).
constexpr
не означает, что функция всегда используется в постоянном выражении, это означает, что функция может использоваться в постоянном выражении.
(Существуют аналогичные примеры, включающие функции без шаблонов.)
Ответ 2
В дополнение к предыдущим ответам: constexpr на функции ограничивает
его реализация значительно: его тело должно быть видимым компилятору
(inline) и должен состоять только из одного оператора return. я бы
удивлен, если вы можете правильно реализовать sqrt() или sin()
выполните это последнее условие.
Ответ 3
constexpr
функции не pure
, потому что constexpr
является подсказкой для компилятора, что функция может быть вычислена во время компиляции, если ее аргументы являются константами и операция, упомянутая в теле функции, для этих аргументы, сами constexpr
.
Последний, используя код шаблона, позволяет нам продемонстрировать нечистую функцию constexpr
:
template <typename T>
constexpr T add(T lhs, T rhs) { return lhs + rhs; }
созданный с помощью этого типа
DebugInteger operator+(DebugInteger lhs, DebugInteger rhs) {
printf("operator+ %i %i", lhs._value, rhs._value);
return DebugInteger(lhs._value + rhs._value);
}
Здесь operator+
не является constexpr и, следовательно, может читать/записывать глобальное состояние.
Можно сказать, что функция constexpr
pure
оценивается во время компиляции... но затем она просто заменяется константой в отношении времени выполнения.
Ответ 4
Каждая функция constexpr
чиста, но не каждая чистая функция может или должна быть constexpr
.
[Примеры с шаблонами функций constexpr
вводят в заблуждение, поскольку шаблоны функций не являются функциями, они являются шаблонами, с помощью которых компилятор может генерировать функции. Результатом шаблонов функций, их специализаций, являются функции, и они будут constexpr
если возможно.]
Чистая функция - это функция, которая зависит только от ее аргументов или от другого постоянного состояния. Это в значительной степени функция constexpr
. Кроме того, функции constexpr
должны быть определены (не только объявлены) до их первого использования (рекурсия, кажется, разрешена, хотя) и должна состоять только из оператора return. Этого достаточно, чтобы сделать разрешенное подмножество Turing-complete, но результат не обязательно является наиболее эффективной формой во время выполнения.
Это приводит нас к математическим функциям. Вероятно, вы можете реализовать constexpr
sqrt()
или sin()
, но им придется использовать рекурсивную реализацию, которую компилятор может оценить во время компиляции, тогда как во время выполнения они будут лучше реализованы в одной операции ассемблера. Поскольку constexpr
использование sqrt()
и sin()
немного и далеко друг от друга, лучше использовать максимальную производительность во время выполнения, для чего требуется форма, которая не способна constexpr
.
Вы можете задаться вопросом, почему вы не можете написать одну версию функции constexpr
и функцию, используемую во время выполнения, и я бы согласился с тем, что было бы неплохо иметь, но стандарт говорит, что вы не можете перегрузить constexpr
Несс. Возможно, в С++ 17...