编译时已知条件下的标准if/else

Standard if/else on conditions known at compile-time?

本文关键字:标准 if else 条件下 编译      更新时间:2023-10-16

我知道C++中的一些元编程技术,可以在编译时计算常量。元函数中的大部分时间分支是通过三元运算符完成的,与标准if/else相反,三元运算符可以在编译时进行求值。

但关于这类功能:

template <unsigned int N>
void f()
{
    if (N == 0) {
        // Some computations here
    } else if (N <= 42) {
        // Some computations here
    } else {
        // Some computations here
    }
}

编译器将做什么(假设-O3)?编译器知道f<0>()在第一种情况下总是分支,f<32>()在第二种情况下始终分支,而f<64>()在第三种情况下一直分支。

编译器会删除始终为false的分支吗?它会直接分支到唯一有效的案例吗?

优化器将删除分支和未使用的分支中的代码,但要注意:编译器需要在优化器有机会查看代码之前处理函数,这意味着所有分支对于N的所有值都必须是有效的(可编译的)。

例如,如果第二个分支包含:

} else if (N <= 42) {
   char data[50 - N];
// other code

编译器将无法实例化N >= 50的模板,即使优化器将删除该分支。

我在http://gcc.godbolt.org/,是一个显示生成的程序集的联机编译器。您可以将自己的编译器与它支持的任何开关一起使用,以输出程序集。

volatile int i;
template <unsigned int N>
void f()
{
    if (N == 0) {
        i = 1;
    } else if (N <= 42) {
        i = 2;
    } else {
        i = 3;
    }
}
template void f<0>();
template void f<10>();
template void f<100>();

这是我拿到的

void f<0u>():                           # @void f<0u>()
    movl    $1, i
    ret
void f<10u>():                          # @void f<10u>()
    movl    $2, i
    ret
void f<100u>():                         # @void f<100u>()
    movl    $3, i
    ret
i:
    .long   0                       # 0x0

正如您所看到的,每个实例化都删除了所有的死代码。

事实上,此代码是在禁用优化的情况下生成的;我使用的编译器(clang)一开始并没有为死代码生成指令。其他编译器的行为可能有所不同。您必须自己测试编译器的行为。