Связь между constexpr и чистыми функциями - PullRequest
18 голосов
/ 28 марта 2011

Прав ли я, что:

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

И если так, то почему функции <cmath> не определены с constexpr?

Ответы [ 4 ]

17 голосов
/ 28 марта 2011

Чтобы добавить к тому, что сказали другие, рассмотрим следующий constexpr шаблон функции:

template <typename T>
constexpr T add(T x, T y) { return x + y; }

Этот шаблон функции constexpr может использоваться в постоянном выражении в некоторых случаях (например, где T is int), но не в других (например, где T - это тип класса с перегрузкой operator+, которая не объявлена ​​constexpr).

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

(Есть похожие примеры использования нетекстовых функций.)

9 голосов
/ 28 марта 2011

В дополнение к предыдущим ответам: constexpr для функции сильно ограничивает ее реализацию: ее тело должно быть видимым для компилятора (inline) и должно состоять только из одного оператора return.Я был бы удивлен, если бы вы могли правильно реализовать sqrt () или sin () и при этом соответствовать этому последнему условию.

7 голосов
/ 28 марта 2011

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 при оценке во время компиляции ... но затем он просто заменяется константой, что касается времени выполнения.

0 голосов
/ 15 июня 2012

Каждая constexpr функция является чистой, но не каждая чистая функция может или должна быть constexpr.

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

Чистая функция - это функция, зависящая только от ее аргументов или другого постоянного состояния. Это почти то же самое, что и функция constexpr. Кроме того, функции constexpr должны быть определены (а не только объявлены) до их первого использования (хотя рекурсия представляется разрешенной) и должны состоять только из оператора return. Этого достаточно, чтобы сделать допустимое подмножество Тьюринга полным, но результат не обязательно является наиболее эффективной формой во время выполнения.

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

Вы можете задаться вопросом, почему вы не можете написать одну constexpr версию функции и ту, которая используется во время выполнения, и я согласился бы, что было бы неплохо это иметь, но стандарт говорит, что вы не можете перегружать constexpr Несс. Может быть, в C ++ 17 ...

...