考虑这个代码片段。
#include <iostream>
struct A {
void f() { std::cout << "f"; }
void g() { std::cout << "g"; }
template <bool b>
void call() { (b ? f() : g()); }
};
int main()
{
A().call<true>();
}
根据 template
传给 call
,要么 f
或 g
将被调用。我的问题是,如果编译器以某种方式被迫对if条件进行预评估。考虑一下这个其他可能的实现 call
:
template <bool b>
void call() {
bool x = b;
(x ? f() : g());
}
在这种情况下,编译时模板首先被转换为运行时变量,然后才决定是否使用该模板。f
或 g
是做的。我认为,在这种情况下,编译器将无法删除if语句。
事实上,如果我用 榫头 似乎正是这种情况。
标准中是否有某些部分定义了哪些模板表达式?有 在编译时评估?
(当然,在这个简单的例子中,我可以很容易地写出针对 b == true
和 b == false
但这不是这个问题的关键。)
所有模板表达式都是在编译时评估的,因为模板在运行时不存在。你可以使用 if constexpr
在编译时,它被认为会被评估。
template <bool b>
void call() { if constexpr (b) f(); else g(); }
在你的例子中(对于 b = true
)这将成为
void call() { f(); }
无论优化程度如何。
然而当你使用普通的 if
或三元运算符,生成的代码可能很容易被优化。在您的例子中(同样是针对 b=true
)模板实例创建了这样的东西。
void call() { (true ? f() : g()); }
如果你允许的话,编译器可以很容易地优化它。G++与 -O3
例如,只是删除了 A
和呼吁 call
囫囵吞枣 std::cout << "f"
变成 main
. 见上 榫头.
凝结。所有模板表达式在编译时都会被评估,但编译器可以识别一个表达式或变量是否是常量,并能够优化这种情况,但编译器没有义务这样做(当你试图调试某些东西时,你不希望优化代码)。