C++ constexpr 表达式求值
C++ 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
分支和 return 0。当然可以使用 enable_if
或其他任何方式重写它,但我只想知道以下内容:
当涉及到子表达式类型评估时,这个声明是无效的吗?
即使上面的语句声称子表达式未被计算,为什么这会失败?我想无论如何都必须评估类型(例如,检查是否满足条件的两个分支都具有相同类型的要求),因此它以无限模板实例化结束。正确的假设?
c++ 标准中有描述这种行为的地方吗?
您误解了评估某事的含义。评估是在执行时发生的事情(即使该执行是在编译器 运行 时发生的)。
模板实例化是您代码的 static 属性。如果你写 times<N-1>
你要求实例化该模板。是否调用该函数并不重要;你写实例化,所以它被实例化。
这就是递归元编程通常通过模板特化来处理终端情况的原因。
这就是 if constexpr
被添加到 C++17 的原因。因为它有能力,不仅有条件地评估语句,而且有条件地 discard 语句,使另一个分支实际上不存在。这是以前不存在的东西。这允许另一个分支包含本来静态错误的代码。
所以这行得通:
if constexpr(N < 0) return 0 else return y+times<N-1>(y);
第二个子句将被丢弃,因此不会被实例化。
所以这个说法是正确的;子表达式有条件地求值。你只是误解了它如何适用于你的情况。
我对以下关于 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
分支和 return 0。当然可以使用 enable_if
或其他任何方式重写它,但我只想知道以下内容:
当涉及到子表达式类型评估时,这个声明是无效的吗?
即使上面的语句声称子表达式未被计算,为什么这会失败?我想无论如何都必须评估类型(例如,检查是否满足条件的两个分支都具有相同类型的要求),因此它以无限模板实例化结束。正确的假设?
c++ 标准中有描述这种行为的地方吗?
您误解了评估某事的含义。评估是在执行时发生的事情(即使该执行是在编译器 运行 时发生的)。
模板实例化是您代码的 static 属性。如果你写 times<N-1>
你要求实例化该模板。是否调用该函数并不重要;你写实例化,所以它被实例化。
这就是递归元编程通常通过模板特化来处理终端情况的原因。
这就是 if constexpr
被添加到 C++17 的原因。因为它有能力,不仅有条件地评估语句,而且有条件地 discard 语句,使另一个分支实际上不存在。这是以前不存在的东西。这允许另一个分支包含本来静态错误的代码。
所以这行得通:
if constexpr(N < 0) return 0 else return y+times<N-1>(y);
第二个子句将被丢弃,因此不会被实例化。
所以这个说法是正确的;子表达式有条件地求值。你只是误解了它如何适用于你的情况。