C++ 中 if/else 分支的编译时消除

Igo*_*hov 12 c++ templates compiler-optimization template-specialization language-lawyer

在下面的代码示例中,if语句依赖于bool模板参数,它是一个编译时常量。编译器以不同的方式处理此代码:

  • MSVC 因链接错误而失败(这是我所期望的),因为else分支中的模板函数缺乏true模板参数值的专业化(即使它从未被调用)。

  • GCC 和 Clang 编译时都没有问题,并且运行时行为是正确的。这显然是因为它们if在编译时评估语句并在链接之前删除未使用的分支。

问题是哪种行为符合标准(或者它是未定义的行为并且两者都以自己的方式正确)?

#include <iostream>

template<const bool condition>
struct Struct
{
    void print()
    {
        if (condition)
        {
            std::cout << "True\n";
        }
        else
        {
            printIfFalse();
        }
    }

private:
    void printIfFalse();
};

template <>
void Struct<false>::printIfFalse()
{
    std::cout << "False\n";
}

int main()
{
    Struct<true> withTrue{};
    withTrue.print();

    Struct<false> withFalse{};
    withFalse.print();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

wal*_*nut 14

所有编译器的行为都正确。

你的程序是形成不良的,没有诊断需要,因为你ODR-使用Struct<true>::printIfFalse过的实例Struct<true>::print()从呼叫所需withTrue.print();。在废弃语句之外使用 odr 的函数必须在程序中有定义,参见[basic.def.odr]/4,否则程序格式错误,无需诊断

一个废弃的语句是你所得到的,如果你使用if constexpr的模板和声明是不是在选择分支。所以,你可以做,使良好形成的方案是使用if constexpr替代if。这是一个 C++17 特性。