constexpr与纯函数之间的关系

时间:2011-03-28 16:56:40

标签: c++ c++11 constexpr

我是对的,那个:

  • 使用constexpr定义的任何功能都是pure function
  • 任何纯函数都可以并且必须使用constexpr定义,如果它对编译器来说不是很昂贵。

如果是这样,为什么<cmath>的函数不是用constexpr定义的?

4 个答案:

答案 0 :(得分:17)

要添加其他人所说的内容,请考虑以下constexpr函数模板:

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

constexpr函数模板在某些情况下可用于常量表达式(例如,Tint)但在其他情况下不可用(例如,Toperator+具有constexpr重载但未声明为constexpr的类类型。

{{1}}并不意味着函数始终可用于常量表达式,这意味着函数可能可用于常量表达式。< / p>

(有类似的例子涉及非模板函数。)

答案 1 :(得分:9)

除了以前的答案:constexpr对函数的限制 它的实现很大:它的主体必须对编译器可见 (内联),并且必须仅包含一个return语句。我会 如果你能正确地实现sqrt()或sin(),那就很惊讶了 满足最后的条件。

答案 2 :(得分:7)

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 ...但就运行时而言,它只是被一个常量替换。

答案 3 :(得分:-1)

每个constexpr函数都是纯函数,但不是每个纯函数都可以或应该是constexpr

[涉及constexpr函数模板的示例具有误导性,因为函数模板不是函数,它们是编译器可以生成函数的模式。函数模板的结果,它们的特化,函数,如果可能,它们 constexpr。]

纯函数是仅依赖于其参数或其他常量状态的函数。这几乎就是constexpr函数。此外,constexpr函数必须在第一次使用之前定义(不仅声明)(但似乎允许递归),并且必须仅包含return语句。这足以使得允许的子集Turing-complete,但结果不一定是运行时最有效的形式。

这将我们带到了数学函数。您可以实现constexpr sqrt()sin(),但是他们必须使用编译器可以在编译时评估的递归实现,而在运行时,这些实现更好一个汇编操作。由于constexprsqrt()的{​​{1}}使用很少且距离较远,因此最好最大限度地提高运行时性能,这需要一个不具有sin()能力的表单。

你可能想知道为什么你不能写一个constexpr版本的函数和一个在运行时使用的版本,我同意这样做很好,但标准说你不能超载在constexpr上。也许在C ++ 17 ...