模板bool参数的功能:保证优化?

时间:2017-02-14 14:23:08

标签: c++ templates

在下面的模板化函数示例中,if循环中的中心for是否保证优化,只留下使用过的指令?

如果不能保证优化(在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;

}

3 个答案:

答案 0 :(得分:4)

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

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

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

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

答案 1 :(得分:1)

无法保证它会被优化掉。虽然它是一个编译时常量,但它很有可能存在。

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

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

答案 2 :(得分: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中看到它。

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