John Jiang
John Jiang

Reputation: 955

Can c++ compiler optimization generate two versions of a function with respect to a boolean argument?

I have a function f(int x, float y, char* z, .., bool b). The argument b is used only in the fashion of:

if (b) {
 ...
} else {
 ...
}

in various parts of the function body. For efficiency reason, I would like to effectively create two functions f0 and f1, where b is set to false and true respectively, to avoid evaluating the conditional at run time. At the same time since the implementation of f is fairly long, I don't want to explicitly define f0 and f1 separately. Is there any compiler optimization feature that automatically spawns these two branch functions at compile time?

Maybe there are better design patterns that avoid this line of thinking completely? Keep in mind that the conditional b can be evaluated in a massive loop.

Upvotes: 1

Views: 246

Answers (2)

Jarod42
Jarod42

Reputation: 217810

Template allows to factorize this kind of code, and C++17 allows it cleanly with if constexpr:

template<bool b>
void f(int x, float y, char *z)
{
    // ...
    if constexpr (b)
    {
        // ...
    }
    else
    {
        // ...
    }
    // ...
}

// if you still need runtime dispatch
void f(int x, float y, char *z, bool b)
{
    return b ? f<true>(x, y, z) : f<false>(x, y, z);
}

Without if constexpr, it is not guaranty that there are no branch at runtime, but compiler might easily do it normally. So if you want that guaranty pre-C++17, you have to specialize divergent part

  • by specialization:

    template <bool b> void f_impl(..);
    
    template <> void f_impl<true>(..)  { /*..*/ }
    template <> void f_impl<false>(..) { /*..*/ }
    
    template<bool b>
    void f(int x, float y, char *z)
    {
        // ...
        f_impl<b>(..);
        // ...
    }
    
  • or tag dispatching:

    void f_impl(std::true_type, ..)  { /*..*/ }
    void f_impl(std::false_type, ..) { /*..*/ }
    
    template<bool b>
    void f(int x, float y, char *z)
    {
        // ...
        f_impl(std::integral_constant<bool, b>{}..); // std::bool_constant<b> in C++17 
        // ...
    }
    

Upvotes: 3

Sid S
Sid S

Reputation: 6125

Use a template:

template<bool b>
void f(int x, float y, char *z)
{
    if (b)
    {
        ...
    }
    else
    {
        ...
    }
}

...
if (runtimeCondition)
{
    f<true>(1, 2, "");
}
else
{
    f<false>(1, 2, "");
}

Upvotes: 2

Related Questions