22

假设我有一个功能:

template <bool stuff>
inline void doSomething() {
    if(stuff) {
        cout << "Hello" << endl;
    }
    else {
        cout << "Goodbye" << endl;
    }
}

我这样称呼它:

doSomething<true>();
doSomething<false>();

它会弹出:

Hello
Goodbye

我真正想知道的是编译器是否完全优化了这个?当我用 true 调用模板化函数时,它会创建一个只输出“Hello”并避免 if 语句和“Goodbye”代码的函数吗?

这对于我刚刚编写的这个巨大的函数非常有用,它应该是非常优化的,并且尽可能地避免了不必要的 if 语句检查。我有一种很好的感觉,至少在带有优化的发布版本中,如果不是在没有优化的调试版本中。

4

5 回答 5

17

免责声明:没有人可以保证任何事情。

也就是说,对于任何编译器来说,这都是一个明显而简单的优化。可以肯定地说,它将被优化掉,除非优化器实际上是无用的。

由于您的“真”和“假”是常量,因此您明确地在每个类中创建了一个明显的死分支,编译器应该优化它。应该在这里按字面意思理解 - 如果“优化”编译器没有删除死分支,我会认为这是一个主要的主要问题。

换句话说,如果您的编译器无法对此进行优化,那么应该评估的是该编译器的使用,而不是代码。

所以,我想说你的直觉是正确的:虽然是的,不能对每个编译器做出这样的“保证”,但我不会使用无法在任何生产环境中执行简单优化的编译器,当然也不会在任何对性能至关重要的。(当然在发布版本中)。

所以,使用它。任何现代优化编译器都会将其优化掉,因为它是一种微不足道的优化。如果有疑问,请检查反汇编,如果未优化,请将编译器更改为更现代的编译器。

一般来说,如果您正在编写任何类型的性能关键代码,您必须至少在某种程度上依赖编译器优化。

于 2012-08-25T12:13:29.770 回答
3

这本质上取决于编译器,因此您必须检查编译器的文档或生成的代码。但是在像这样的简单情况下,您可以轻松地自己实现优化:

template <bool stuff>
inline void doSomething();

template<>
inline void doSomething<true>() {
    cout << "Hello" << endl;
}

template<>
inline void doSomething<false>() {
    cout << "Goodbye" << endl;
}

但是“优化”并不是一个真正合适的词,因为这实际上可能会降低性能。如果它确实有益于您的代码性能,它只是一种优化。

于 2012-08-19T22:40:29.350 回答
1

确实,它确实创建了两个功能,但是

过早优化是万恶之源

特别是如果您因为一个简单的 if 语句而更改了代码结构。我怀疑这会影响性能。此外,布尔值必须是静态的,这意味着您不能获取运行时评估的 var 并将其传递给函数。链接器应该如何知道要调用哪个函数?在这种情况下,您必须手动评估它并自行调用相应的函数。

于 2012-08-19T22:37:13.230 回答
1

编译器非常擅长不断折叠。也就是说,在这种情况下,如果检查会一直保留到优化之后,我会感到惊讶。未优化的构建可能仍然有检查。最简单的验证方法是创建汇编程序输出并检查。

也就是说,值得注意的是编译器必须检查两个分支的正确性,即使它只使用一个分支。这经常出现,例如,当对随机访问迭代器和其他迭代器使用稍微不同的算法时。该条件将取决于类型特征,并且其中一个分支可能无法编译,具体取决于特征测试的操作。委员会已经讨论过在静态术语下关闭这种检查,如果虽然没有达成共识,但是关于功能的外观如何(如果它被添加)。

于 2012-08-19T23:01:13.393 回答
0

如果我对您的理解正确,您希望(本质上)最终得到“两个”功能,这些功能针对真或假输入进行了优化,以便他们不需要检查该标志?

除了可能产生的任何微不足道的优化(我反对过早的优化 - 我相信在优化之前测量之前的可维护性),我会说为什么不将你的函数重构为实际上是两个函数呢?如果他们有共同的代码,那么该代码也可以被重构出来。但是,如果要求是重构不是最佳的,那么我将用#define 重构替换它。

于 2012-08-19T22:37:24.633 回答