我对以下有关 constexpr 函数中使用的条件表达式的评论有疑问:
A branch of a conditional expression that is not taken in a constexpr function is not evaluated. Source: 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++ 标准中是否有地方描述此行为?
最佳答案
您误解了评估某事的含义。评估是在执行时发生的事情(即使该执行发生在编译器运行时)。
模板实例化是代码的静态属性。如果你写times<N-1>
您要求实例化该模板。是否调用该函数并不重要;您编写实例化,因此它会被实例化。
这就是为什么递归元编程通常通过模板专门化来处理终端情况。
这就是为什么 if constexpr
已添加到 C++17 中。因为它不仅有能力有条件地评估语句,而且有条件地丢弃语句,使另一个分支实际上不存在。这以前是不存在的。这允许另一个分支包含否则静态形成的代码。
所以这会起作用:
if constexpr(N < 0) return 0 else return y+times<N-1>(y);
第二个子句将被丢弃,因此不会被实例化。
所以这个说法是正确的;子表达式是有条件评估的。您只是误解了它如何适用于您的案例。
关于C++ constexpr 表达式求值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42676391/