根据编译器优化和代码性能,`if constexpr` 与 `if`

`if constexpr` vs `if` in light of compiler optimization and code performance

考虑一个对性能非常关键的函数模板func。它可以用 T=Type1 或其他类型实例化。部分功能逻辑取决于T它被实例化。

可以显式使用 if constexpr(代码 B)或改用普通的 if(代码 A),而编译器 可能 优化了代码。

但是,我想知道,没有constexpr(代码A)的实现有什么不同?编译器 是否能够 检测 if 的哪个分支(在代码 A 中)在编译时实例化时使用? 它仍然可以(对于代码 A)生成效率较低的代码吗?

代码A。没有 if constexpr:

template<class T>
void func(T argument)
{
    // some general type-independent logic
    if (std::is_same<Type1,T>::value)
    {
        // do something
    }
    else
    {
        // do something else
    }
    // some general type-independent logic
}

代码B。 if constexpr:

template<class T>
void func(T argument)
{
    // some general type-independent logic
    if constexpr (std::is_same<Type1,T>::value)
    {
        // do something
    }
    else
    {
        // do something else
    }
    // some general type-independent logic
}

代码 A 和 B 都可以编译,因为 do somethingdo something else 对于任何 T.

都是格式正确的

有一些类似的问题:

如果出于某种原因代码 B 比代码 A 更可取(无论如何两个分支都是良构的),上述问题不会回答。

我看到的唯一优势是明确告诉程序员这个 if 是编译时的;但是,我会说条件表达式是不言自明的。

if constexpr 不是为了优化。编译器非常擅长优化 if (true)if (false) 的分支(因为我们谈论的是常量表达式,这就是它的归结)。这是 OP 中示例的 godbolt demo - 你会注意到 gcc 和 clang,即使在 -O0 上,也不会为简单的 if.[=29= 发出分支]

if constexpr 就是确保只有 if 的一个分支被 实例化 。这对于编写模板非常重要和有价值——因为现在我们实际上可以在同一个函数体内编写条件编译代码,而不是为了避免实例化而编写多个人工函数。

就是说,如果您有一个已知常量表达式的条件 - 只需始终使用 if constexpr,无论您是否需要实例化的好处。这样的决定没有任何不利之处。它让读者更清楚这个条件确实是不变的(否则它甚至不会编译)。它还会强制将表达式计算为常量(slight variant 导致 gcc 在 -O0 处发出一个分支,而不是在 -O1 处),这与即将添加的 is_constant_evaluated() 可能在长 运行 中变得更重要(甚至可能否定我的开头段落)。


The only advantage I see would be to tell the programmer explicitly that this if is compile-time; however, I would say the conditional expression is self-explanatory.

具体来说,是的,std::is_same<X, Y>::value是"self-explanatory",它是一个常量表达式...因为我们碰巧熟悉std::is_same。但是 foo<X>::value 是常量表达式还是 foo<X>() + bar<Y>() 是常量表达式还是比这更复杂的东西就不那么明显了。

它看到 if constexpr 这使得它是编译时不言自明的事实,而不是条件本身的内容。