"if constexpr" 在模板之外有用吗?

Is "if constexpr" useful outside of templates?

我正在尝试完全理解 if constexpr

我明白,如果if constexpr(expr)在模板中使用,并且expr依赖于模板参数,那么在实例化过程中,只有then/[=15之一=] 分支会被实例化,其他的会被丢弃。

我有两个问题:

Is it true, that if expr is not dependent on a template parameter, then no branches of if constexpr(expr) will be discarded? If yes, where does the standard say so? […]

是的,确实如此。您正在寻找 [stmt.if]/2。具体这部分:

[…] During the instantiation of an enclosing templated entity, if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated. […]

我能找到的最好的例子是 cppreference.com:

template<class T> void g() {
    auto lm = [](auto p) {
        if constexpr (sizeof(T) == 1 && sizeof p == 1) {
           // this condition remains value-dependent after instantiation of g<T>
        }
    };
}

Is if constexpr useful outside of templates? If yes, can you give some examples to understand its usefulness?

虽然当 if constexpr 没有出现在模板内部时所有分支都将被实例化,但 [basic.def.odr]/10 仍然适用:

Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement; […]

强调我的。这实际上意味着在丢弃的语句中对实体的 ODR 使用不算数。例如:

void blub();

constexpr bool use_blub = false;

void f()
{
    if constexpr (use_blub)
    {
        blub();
    }
}

如果条件为假,对blub() 的调用将不需要您的程序定义blub()。使用普通的 if,程序仍然需要在某处提供 blub() 的定义,即使从未使用过。因此,例如,您可以使用 if constexpr 在调用某些库函数和调用某些回退实现之间切换,具体取决于库是否可用(并被链接到)。除此之外,假设编译器可能不会警告无法访问的代码,如果它由于 if constexpr 而无法访问,就像它可能与正常的 if 一样。然而,我无法使用任何实际的编译器想出一个这样的例子……