优化开关(x),x是作为参数传递的常数

cpp*_*ner 1 c++ optimization enums switch-statement c++14

我得打电话f(0)f(1).
参数(01)仅用于switch-case.
如何尽可能强制/指导编译器优化开关盒(从"昂贵"到"便宜"版本)?

godbolt演示开始,switch-case没有经过优化.

示例:昂贵

int f(int n) {
    switch(n) {
        case 0: {
            return 5;
        };break;

        case 1: {
            return 10;
        };break;
    }

    return 15;
}

int main(){
    f(0);
}
Run Code Online (Sandbox Code Playgroud)

示例:便宜(我的梦想)

int f0(){
    return 5;
}

int f1(){
    return 10;
}

int main(){
    f0();
}
Run Code Online (Sandbox Code Playgroud)

更多信息 :-

在实际情况中,不仅仅是0和1 - 它们是枚举类.
该参数在用户方面总是不变的,例如f(CALLBACK_BEGIN),f(CALLBACK_END).

为什么我不能只是f0()/ f1()?

我想将它组合成一个函数,因为我有时想要创建一个传递函数.如果我可以编码它,它更容易维护: -

int g(int n){  .... }
int f(int n){  return g(n); }
Run Code Online (Sandbox Code Playgroud)

它比以下更容易维护: -

int g0(){ .... }    int g1(){ .... }
int f0(){  return g0(); }
int f1(){  return g1(); }
Run Code Online (Sandbox Code Playgroud)

我也更喜欢避免模板,所以我不能在优化模板替换开关时使用解决方案.我的理由是: -

  • 模板必须在标头中实现.
  • 我需要它.cpp,所以我必须将它间接到另一个非模板函数.
    它变得很脏很快.

过早优化?

就我而言,它被称为每秒60*10000 +次.

编辑

我误解了godbolt演示的结果.它实际上是优化的.
(感谢MMBenoît指出它.)

EDIT2

收到两个很好的答案后,我测试了它,发现Visual C++非常聪明.
它可以优化的东西: -

int f(int p1,int p2){
    if(p1==0 && p2==1){  //zero cost

    }
}
f(0,1);  //inside main
Run Code Online (Sandbox Code Playgroud)

在实际情况中,有3-5层功能间接,但Visual C++仍然可以找到!

结果与类似的帖子一致:循环中的常量条件:编译器优化

Gui*_*cot 8

一个简单的解决方案是制作您的功能constexpr,这可以大大简化优化.

//  v--- that
constexpr int f(int n) {
    switch(n) {
        case 0: {
            return 5;
        };break;

        case 1: {
            return 10;
        };break;
    }

    return 15;
}
Run Code Online (Sandbox Code Playgroud)

这使得函数在编译时可调用.如果传递constexpr值的参数,则编译过程中编译器可以执行该函数.由于您将枚举值作为参数传递,因此很可能在编译时执行该函数.

如果您的繁重函数需要一些运行时值,请尝试分解可以标记为constexpr的部分,并且可能使用模板(它们确实有助于使代码更快!)

constexpr int const_part_of_f(int n) {
    switch(n) {
        case 0: {
            return 5;
        };break;

        case 1: {
            return 10;
        };break;
    }
}

template<int n>
int f() {
    if (get_runtime_value()) {
        // Since `n` is a compile time constant, the result of `const_part_of_f` is
        // evaluated at compile time, even if `f` is not a constexpr function.
        return const_part_of_f(n)
    }

    return 15;
}
Run Code Online (Sandbox Code Playgroud)

如果您真的想帮助优化器,请避免过多的内存分配.例如,如果需要在编译时已知的特定大小的数组,请使用std::array而不是std::vector.

正如其他用户所指出的,二进制膨胀是为了初始化iostream全局变量.然而,这并不否认constexpr函数更容易被编译器优化的事实.