C ++ constexpr表达式评估

时间:2017-03-08 16:13:23

标签: c++ c++11 templates constexpr expression-evaluation

关于constexpr函数中使用的条件表达式的注释,我有一个问题:

  

不评估未在constexpr函数中使用的条件表达式的分支。 来源: conditional evaluation of functions

如前所述,您可以使用constexpr函数,例如

constexpr int check(int i) {
    return (0<=i && i<10) ? i : throw out_of_range();
}

并且仅评估所采用的分支。到现在为止还挺好。但是为什么这与模板结合无效。所以我们在这里采用这个基本的例子:

template <int N>
constexpr int times(int y) {
    return (N<0) ? 0 : y+times<N-1>(y);
}

times<5>(10);

编译失败,因为模板实例化深度超过了最大值,即使条件的false分支仅采用了4次。然后它应该取true分支并返回0.当然它可以使用enable_if或其他任何东西重写,但我只想知道以下事项:

  • 当涉及子表达式类型评估时,此语句是否无效?

  • 为什么即使上述声明声称子表达式未被评估,这也会失败?我想无论如何都必须评估类型(例如,检查是否满足条件的两个分支具有相同类型的要求),因此它以无限模板实例化结束。正确的假设?

  • c ++标准中是否有描述此行为的地方?

1 个答案:

答案 0 :(得分:2)

你误解了评估某事的意义。评估是在执行时发生的事情(即使在编译器运行时发生执行)。

模板实例化是代码的静态属性。如果您编写times<N-1>,则要求实例化该模板。如果你打电话给那个功能并不重要;你编写了实例化,所以它被实例化了。

这就是递归元编程通常通过模板特化处理终端案例的原因。

这就是将if constexpr添加到C ++ 17的原因。因为它有权,不仅有条件地评估语句,而且有条件地 discard 语句,使得其他分支实际上不存在。这不是以前曾经存在过的东西。这允许另一个分支包含本来是静态形成的代码。

所以这会奏效:

if constexpr(N < 0) return 0 else return y+times<N-1>(y);

第二个子句将被丢弃,因此不会被实例化。

所以陈述是正确的;子表达式是有条件的评估。你只是误解了它如何适用于你的情况。