C++ constexpr 表达式求值

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

我对以下有关 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/

相关文章:

c++ - 试图调用模板类的友元函数

c++ - 如何从另一个类中的私有(private)指针指向的类中获取私有(private)信息?

c++ - 简单的运算符重载不起作用

c++ - 为什么我仍然可以访问对临时对象的引用?

c++ - std::basic_fstream 和 std::unique_lock 的接口(interface)设计

c++ - Utf-8 编码 visual studios 十进制值

c++ boost模板类型和非类型

c++ - 模板化重载运算符不明确

c++ - 无法断开和重新连接套接字(C++,winsock2)

c++ - 计算小数部分并以精确的方式显示小数点后的数字