【问题标题】:Standard if/else on conditions known at compile-time?编译时已知条件的标准 if/else?
【发布时间】:2013-07-09 18:22:25
【问题描述】:

我知道 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&lt;0&gt;() 总是在第一种情况下分支,f&lt;32&gt;() 总是在第二种情况下分支,f&lt;64&gt;() 总是在第三种情况下分支。

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

【问题讨论】:

  • 是的,现代编译器会删除无用的分支。
  • 说...如果你想保证,那么简单地使用 template specialization 并说:template &lt;...&gt; void f&lt;0&gt;( /* computation for 0 */ } 等等。让它绝对、明确、独立于编译器地清楚你想要什么?

标签: c++ templates optimization if-statement c++11


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

    我在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)首先不会为死代码生成指令。其他编译器的行为可能不同。您必须自己测试自己的编译器的行为。

    【讨论】:

    • 同意调查结果......但是,如果您专门研究编译器的选择,您可以强制执行此操作?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-01
    • 1970-01-01
    • 2013-09-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多