考虑对性能至关重要的功能模板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 something
和do something else
对于任何T
都是格式正确的。
有一些听起来相似的问题:
constexpr if
needed? –在需要constexpr
时回答。if
and constexpr if
–仅列出差异由于某些原因(两个分支的格式正确时),代码B优于代码A,上述问题无法回答。
我看到的唯一好处是明确告诉程序员该if
是编译时的;但是,我会说条件表达式是不言自明的。
答案 0 :(得分:9)
if constexpr
与优化无关。编译器非常擅长优化if (true)
或if (false)
的分支(由于我们在谈论常量表达式,因此可以归结为它)。这是OP中示例的godbolt demo-您会注意到,即使在-O0
上,gcc和clang都不会为简单的if
发出分支。
if constexpr
是关于确保if
中只有一个分支被实例化。这对于编写模板非常重要且很有价值-因为现在我们实际上可以在同一个函数的主体内编写有条件的编译代码,而不必编写多个人工函数,而只是为了避免实例化。
也就是说,如果您的条件是已知的常量表达式-始终使用if constexpr
,无论您是否需要实例化好处。这样的决定没有不利之处。使读者更清楚地知道该条件确实是恒定的(因为否则它甚至不会编译)。它还会强制将表达式的计算结果视为常量(slight variant会导致gcc在-O0
发出分支,而不是在-O1
发出分支),并随即将添加{{ 1}}从长远来看可能会变得越来越重要(甚至可能会否定我的开头段落)。
我看到的唯一好处是,可以清楚地告诉程序员这是否是编译时的。但是,我会说条件表达式是不言自明的。
要专门解决这个问题,是的,is_constant_evaluated()
是一个“常量表达式”,这是“不言自明的……”,因为我们碰巧熟悉std::is_same<X, Y>::value
。但是,std::is_same
是一个常量表达式还是foo<X>::value
是一个常量表达式还是比它更任意复杂的事情还不太明显。
看到foo<X>() + bar<Y>()
使得事实证明它是编译时不言自明的,而不是条件本身的内容。