Igor Tolmachov
Igor Tolmachov

Reputation: 144

Compile-time elimination of if/else branch in C++

In the following code sample, the if statement depends on bool template parameter, which is a compile-time constant. Compilers handle this code differently:

The question is which behaviour is standard-compliant (or is it an undefined behaviour and both are correct in their own way)?

#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;
}

Upvotes: 12

Views: 1593

Answers (1)

walnut
walnut

Reputation: 22152

All compilers behave correctly.

Your program is ill-formed, no diagnostic required, because you are odr-using Struct<true>::printIfFalse through the instantiation of Struct<true>::print() required from the call in withTrue.print();. A function that is odr-used outside of a discarded statement must have a definition in the program, see [basic.def.odr]/4, otherwise the program is ill-formed, no diagnostic required.

A discarded statement is what you get if you use if constexpr in a template and the statement is not in the chosen branch. So, what you can do to make the program well-formed is to use if constexpr instead of if. This is a C++17 feature.

Upvotes: 14

Related Questions