c++ - 打开模板参数 : does gcc remove the switch?

标签 c++ templates switch-statement

编译器会(或可以吗?)基于模板参数的 switch 语句?

例如,请参见以下函数,其中模板参数 funcStep1 用于选择适当的函数。这个 switch 语句是否会被删除,因为它的参数在编译时是已知的?我试图从汇编代码(下面给出)中学习它,但我还没有阅读汇编的经验,所以这对我来说不是一个真正可行的任务。

这个问题现在对我来说很重要,因为新引入的 if constexpr 提供了一个保证在编译时评估的替代方案。

template<int funcStep1>
double Mdp::expectedCost(int sdx0, int x0, int x1, int adx0, int adx1) const
{
  switch (funcStep1)
  {
    case 1:
    case 3:
      return expectedCost_exact(sdx0, x0, x1, adx0, adx1);

    case 2:
    case 4:
      return expectedCost_approx(sdx0, x0, x1, adx0, adx1);

    default:
      throw string("Unknown value (Mdp::expectedCost.cc)");
  }
}

// Define all the template types we need
template double Mdp::expectedCost<1>(int, int, int, int, int) const;
template double Mdp::expectedCost<2>(int, int, int, int, int) const;
template double Mdp::expectedCost<3>(int, int, int, int, int) const;
template double Mdp::expectedCost<4>(int, int, int, int, int) const;

当使用 gcc -O2 -ffunction-sections 编译上述函数时,您可以在此处找到“objdump -D”的输出:

1expectedCost.o:     file format elf64-x86-64


Disassembly of section .group:

0000000000000000 <.group>:
   0:   01 00                   add    %eax,(%rax)
   2:   00 00                   add    %al,(%rax)
   4:   08 00                   or     %al,(%rax)
   6:   00 00                   add    %al,(%rax)
   8:   09 00                   or     %eax,(%rax)
    ...

Disassembly of section .group:

0000000000000000 <.group>:
   0:   01 00                   add    %eax,(%rax)
   2:   00 00                   add    %al,(%rax)
   4:   0a 00                   or     (%rax),%al
   6:   00 00                   add    %al,(%rax)
   8:   0b 00                   or     (%rax),%eax
    ...

Disassembly of section .group:

0000000000000000 <.group>:
   0:   01 00                   add    %eax,(%rax)
   2:   00 00                   add    %al,(%rax)
   4:   0c 00                   or     $0x0,%al
   6:   00 00                   add    %al,(%rax)
   8:   0d                      .byte 0xd
   9:   00 00                   add    %al,(%rax)
    ...

Disassembly of section .group:

0000000000000000 <.group>:
   0:   01 00                   add    %eax,(%rax)
   2:   00 00                   add    %al,(%rax)
   4:   0e                      (bad)  
   5:   00 00                   add    %al,(%rax)
   7:   00 0f                   add    %cl,(%rdi)
   9:   00 00                   add    %al,(%rax)
    ...

Disassembly of section .bss:

0000000000000000 <_ZStL8__ioinit>:
    ...

Disassembly of section .text._ZNK3Mdp12expectedCostILi1EEEdiiiii:

0000000000000000 <_ZNK3Mdp12expectedCostILi1EEEdiiiii>:
   0:   e9 00 00 00 00          jmpq   5 <_ZNK3Mdp12expectedCostILi1EEEdiiiii+0x5>

Disassembly of section .text._ZNK3Mdp12expectedCostILi2EEEdiiiii:

0000000000000000 <_ZNK3Mdp12expectedCostILi2EEEdiiiii>:
   0:   e9 00 00 00 00          jmpq   5 <_ZNK3Mdp12expectedCostILi2EEEdiiiii+0x5>

Disassembly of section .text._ZNK3Mdp12expectedCostILi3EEEdiiiii:

0000000000000000 <_ZNK3Mdp12expectedCostILi3EEEdiiiii>:
   0:   e9 00 00 00 00          jmpq   5 <_ZNK3Mdp12expectedCostILi3EEEdiiiii+0x5>

Disassembly of section .text._ZNK3Mdp12expectedCostILi4EEEdiiiii:

0000000000000000 <_ZNK3Mdp12expectedCostILi4EEEdiiiii>:
   0:   e9 00 00 00 00          jmpq   5 <_ZNK3Mdp12expectedCostILi4EEEdiiiii+0x5>

Disassembly of section .text.startup._GLOBAL__sub_I_expectedCost.cc:

0000000000000000 <_GLOBAL__sub_I_expectedCost.cc>:
   0:   48 8d 3d 00 00 00 00    lea    0x0(%rip),%rdi        # 7 <_GLOBAL__sub_I_expectedCost.cc+0x7>
   7:   48 83 ec 08             sub    $0x8,%rsp
   b:   e8 00 00 00 00          callq  10 <_GLOBAL__sub_I_expectedCost.cc+0x10>
  10:   48 8b 3d 00 00 00 00    mov    0x0(%rip),%rdi        # 17 <_GLOBAL__sub_I_expectedCost.cc+0x17>
  17:   48 8d 15 00 00 00 00    lea    0x0(%rip),%rdx        # 1e <_GLOBAL__sub_I_expectedCost.cc+0x1e>
  1e:   48 8d 35 00 00 00 00    lea    0x0(%rip),%rsi        # 25 <_GLOBAL__sub_I_expectedCost.cc+0x25>
  25:   48 83 c4 08             add    $0x8,%rsp
  29:   e9 00 00 00 00          jmpq   2e <_GLOBAL__sub_I_expectedCost.cc+0x2e>

Disassembly of section .init_array:

0000000000000000 <.init_array>:
    ...

Disassembly of section .comment:

0000000000000000 <.comment>:
   0:   00 47 43                add    %al,0x43(%rdi)
   3:   43 3a 20                rex.XB cmp (%r8),%spl
   6:   28 55 62                sub    %dl,0x62(%rbp)
   9:   75 6e                   jne    79 <_ZStL8__ioinit+0x79>
   b:   74 75                   je     82 <_ZStL8__ioinit+0x82>
   d:   20 37                   and    %dh,(%rdi)
   f:   2e 33 2e                xor    %cs:(%rsi),%ebp
  12:   30 2d 32 37 75 62       xor    %ch,0x62753732(%rip)        # 6275374a <_ZStL8__ioinit+0x6275374a>
  18:   75 6e                   jne    88 <_ZStL8__ioinit+0x88>
  1a:   74 75                   je     91 <_ZStL8__ioinit+0x91>
  1c:   31 7e 31                xor    %edi,0x31(%rsi)
  1f:   38 2e                   cmp    %ch,(%rsi)
  21:   30 34 29                xor    %dh,(%rcx,%rbp,1)
  24:   20 37                   and    %dh,(%rdi)
  26:   2e 33 2e                xor    %cs:(%rsi),%ebp
  29:   30 00                   xor    %al,(%rax)

Disassembly of section .eh_frame:

0000000000000000 <.eh_frame>:
   0:   14 00                   adc    $0x0,%al
   2:   00 00                   add    %al,(%rax)
   4:   00 00                   add    %al,(%rax)
   6:   00 00                   add    %al,(%rax)
   8:   01 7a 52                add    %edi,0x52(%rdx)
   b:   00 01                   add    %al,(%rcx)
   d:   78 10                   js     1f <.eh_frame+0x1f>
   f:   01 1b                   add    %ebx,(%rbx)
  11:   0c 07                   or     $0x7,%al
  13:   08 90 01 00 00 10       or     %dl,0x10000001(%rax)
  19:   00 00                   add    %al,(%rax)
  1b:   00 1c 00                add    %bl,(%rax,%rax,1)
  1e:   00 00                   add    %al,(%rax)
  20:   00 00                   add    %al,(%rax)
  22:   00 00                   add    %al,(%rax)
  24:   05 00 00 00 00          add    $0x0,%eax
  29:   00 00                   add    %al,(%rax)
  2b:   00 10                   add    %dl,(%rax)
  2d:   00 00                   add    %al,(%rax)
  2f:   00 30                   add    %dh,(%rax)
  31:   00 00                   add    %al,(%rax)
  33:   00 00                   add    %al,(%rax)
  35:   00 00                   add    %al,(%rax)
  37:   00 05 00 00 00 00       add    %al,0x0(%rip)        # 3d <.eh_frame+0x3d>
  3d:   00 00                   add    %al,(%rax)
  3f:   00 10                   add    %dl,(%rax)
  41:   00 00                   add    %al,(%rax)
  43:   00 44 00 00             add    %al,0x0(%rax,%rax,1)
  47:   00 00                   add    %al,(%rax)
  49:   00 00                   add    %al,(%rax)
  4b:   00 05 00 00 00 00       add    %al,0x0(%rip)        # 51 <.eh_frame+0x51>
  51:   00 00                   add    %al,(%rax)
  53:   00 10                   add    %dl,(%rax)
  55:   00 00                   add    %al,(%rax)
  57:   00 58 00                add    %bl,0x0(%rax)
  5a:   00 00                   add    %al,(%rax)
  5c:   00 00                   add    %al,(%rax)
  5e:   00 00                   add    %al,(%rax)
  60:   05 00 00 00 00          add    $0x0,%eax
  65:   00 00                   add    %al,(%rax)
  67:   00 14 00                add    %dl,(%rax,%rax,1)
  6a:   00 00                   add    %al,(%rax)
  6c:   6c                      insb   (%dx),%es:(%rdi)
  6d:   00 00                   add    %al,(%rax)
  6f:   00 00                   add    %al,(%rax)
  71:   00 00                   add    %al,(%rax)
  73:   00 2e                   add    %ch,(%rsi)
  75:   00 00                   add    %al,(%rax)
  77:   00 00                   add    %al,(%rax)
  79:   4b 0e                   rex.WXB (bad) 
  7b:   10 5e 0e                adc    %bl,0xe(%rsi)
  7e:   08 00                   or     %al,(%rax)

最佳答案

是的,这是优化过的。有一些东西可以使阅读汇编更容易,例如名称分解(例如:_ZNK3Mdp12expectedCostILi1EEEdiiiiidouble Mdp::expectedCost<1>(int, int, int, int, int) const 的分解形式)、剥离注释和文本(并使用 Intel 语法):

double expectedCost<1>(int, int, int, int, int):           # @double expectedCost<1>(int, int, int, int, int)
        jmp     expectedCost_exact(int, int, int, int, int) # TAILCALL
double expectedCost<2>(int, int, int, int, int):           # @double expectedCost<2>(int, int, int, int, int)
        jmp     expectedCost_approx(int, int, int, int, int) # TAILCALL
double expectedCost<3>(int, int, int, int, int):           # @double expectedCost<3>(int, int, int, int, int)
        jmp     expectedCost_exact(int, int, int, int, int) # TAILCALL
double expectedCost<4>(int, int, int, int, int):           # @double expectedCost<4>(int, int, int, int, int)
        jmp     expectedCost_approx(int, int, int, int, int) # TAILCALL

https://godbolt.org/z/ZtoKFH

上述站点为您简化了整个过程。

在这种情况下,我没有提供 expectedCost_approx 的定义所以编译器只是跳转。但无论如何,编译器绝对足够聪明,可以意识到每个模板函数在开关中都有一个常量值。

关于c++ - 打开模板参数 : does gcc remove the switch?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55726326/

相关文章:

多个派生类之间的 C++ 运算符重载

javascript - Switch 语句,它不适用于提示

Javascript 开关范围

c++ - 是否可以在 extern "C" block 内运行 C++ 代码?

c++ - 如何在 Visual Studio (2008) 的特定实例中打开源文件

c++ - 作为左值引用或右值拷贝的数据成员

c++ - 模板中的默认参数 -> 模板参数涉及模板参数

c++ - 使用Throw and Catch的未处理异常运行时错误

c++ - 如何从依赖文件(.d)中消除某些(非系统) header ?

swift - 不同类(class)类型