2017-02-14 30 views
1

在下面的模板函数示例中,for循环内部的中央if保证被优化,只保留使用的指令?带模板布尔参数的函数:保证被优化?

如果不能保证优化(在GCC 4,MSVC 2013和llvm 8.0中),有什么选择,最多使用C++ 11?

请注意,这个函数没有任何用处,我知道这个特定的函数可以通过几种方式进行优化等等。但我想要关注的是如何在生成代码中使用bool模板参数。

template <bool IsMin> 
float IterateOverArray(float* vals, int arraySize) { 

    float ret = (IsMin ? std::numeric_limits<float>::max() : -std::numeric_limits<float>::max()); 

    for (int x = 0; x < arraySize; x++) { 
     // Is this code optimized by the compiler to skip the unnecessary if? 
     if (isMin) { 
      if (ret > vals[x]) ret = vals[x]; 
     } else { 
      if (ret < vals[x]) ret = vals[x]; 
     } 
    } 

    return val; 

} 
+2

我认为这不是优化,因为在C++中几乎没有保证的优化。不过,我希望合理的编译器能够做到这一点,因为它可能会首先生成函数代码并优化它,并且优化'if(true)'应该很容易。 – yeputons

+0

不,但在C++ 17中,你可以使用'如果constexpr(isMin){'。 – flyx

+0

@yeputons ok,编辑我的问题。只有C++ 11有什么好的选择? – manatttta

回答

4

理论上没有。 C++标准允许编译器不仅愚蠢,而且彻头彻尾的敌对。只要抽象机器的行为保持不变,它就可以无条件地注入无用的东西。

实际上,是的。死代码消除和常量分支检测很容易,我检查过的每一个编译器都消除了if分支。

请注意,两个分支都是在一个被删除前编译的,因此它们都必须是完全有效的代码。输出程序集表现为“好像”两个分支都存在,但分支指令(和不可达代码)不是抽象机器行为的可观察特征。

当然,如果不进行优化,可能会留下分支和死代码,因此您可以使用调试器将指令指针移动到“死代码”。

1

不保证它会被优化掉。尽管这是一个编译时间常数,但它有一个很好的机会。

这就是说C++ 17给了我们if constexpr它只会编译通过检查的代码。如果你想要保证,那么我建议你改用这个功能。

在C++之前17如果你只想编译代码的一部分,你需要专门化这个函数,并且只写与那个特化相关的代码。

1

既然你问到在C++ 11这里的替代是一个:

float IterateOverArrayImpl(float* vals, int arraySize, std::false_type) 
{ 
    float ret = -std::numeric_limits<float>::max(); 
    for (int x = 0; x < arraySize; x++) { 
     if (ret < vals[x]) 
      ret = vals[x]; 
    } 
    return ret; 
} 

float IterateOverArrayImpl(float* vals, int arraySize, std::true_type) 
{ 
    float ret = std::numeric_limits<float>::max(); 
    for (int x = 0; x < arraySize; x++) { 
     if (ret > vals[x]) 
      ret = vals[x]; 
    } 
    return ret; 
} 

template <bool IsMin> 
float IterateOverArray(float* vals, int arraySize) { 

    return IterateOverArrayImpl(vals, arraySize, std::integral_constant<bool, IsMin>()); 

} 

你可以看到它在现场here

这个想法是使用函数重载来处理测试。