编译器是否强制根据模板参数计算表达式?

Is the compiler forced to evaluate if expressions depending on template parameters?

本文关键字:参数 计算 表达式 是否 编译器      更新时间:2023-10-16

考虑以下代码片段:

#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>();
}

根据传递给call的参数template,将调用fg。我的问题是,编译器是否以某种方式被迫预先评估 if 条件。考虑call的其他可能实现:

template <bool b>
void call() { 
bool x = b;    
(x ? f() : g()); 
}

在这种情况下,编译时模板首先转换为运行时变量,然后再决定fg。我假设在这种情况下编译器将无法删除 if 语句。

事实上,如果我用 godbolt 测试这种行为,那似乎正是发生的事情。

标准的某些部分是否定义了在编译时必须计算哪些模板表达式?

(当然,在这个简单的例子中,我可以很容易地为b == trueb == 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()); }

如果您允许,编译器可以轻松优化。例如,带有-O3的 G++ 只是删除了A的实例和对call的调用,只是将std::cout << "f"移动到main中。见神电。


Concolusion:所有模板表达式都在编译时计算,但编译器可以识别表达式或变量是否恒定,并且能够优化这种情况,但编译器没有义务这样做(当你尝试调试某些东西时,你不需要优化的代码(