简体   繁体   中英

Is it guaranteed that C++ compiler won't generate branch if the condition depends on the template type and is known at compile time?

Suppose I have this function:

template<typename Side>
int GetSide(std::pair<int, int> i)
{
    if (Side::mIsLeft)
        return i.first;
    else
        return i.second;
}

I see that if mIsLeft is const (even not constexpr ) compiler (gcc/clang) won't generate any branch:

int GetSide<LeftSide>(std::pair<int, int>):
  push rbp
  mov rbp, rsp
  mov QWORD PTR [rbp-16], rdi
  mov eax, DWORD PTR [rbp-16]
  pop rbp
  ret

In contrast to when mIsLeft was NOT const , which a branch would be generated (as expected.)

Now, my question is: Is this behavior (not generating a branch) enforced by standard, or guaranteed in anyway? Or it's just compiler seeing the opportunity and using it? (this is generated even in -O0 ) What if mIsLeft is constexpr would that change anything?

You can check the code here on godbolt .

Why do I care? Before finding this, for a situation like this, I'd use enable_if and have two different template specialization to avoid the unnecessary branch, but this can simplify lots of code.

No, the standard doesn't specify how compilers should generate code. Compilers are allowed to emit a branch even if the condition is a compile-time constant.

On the other hand, these days, optimizing compilers do their best to remove unnecessary branches, so it can be considered a compiler bug, if a compile-time-constant based if doesn't get optimized away.

The details of your specific case are not completely known to us, but in general the answer is no. A const variable can of course be initialized with something that is not known at compile time, eg user input.

You should use a constexpr value and an if constexpr check (if possible in your code base).

Using if constexpr you would discard the branch you don't go in.

Constexpr If

The statement that begins with if constexpr is known as the constexpr if statement.

In a constexpr if statement, the value of condition must be a contextually converted constant expression of type bool. If the value is true, then statement-false is discarded (if present), otherwise, statement-true is discarded.

The return statements in a discarded statement do not participate in function return type deduction:

https://en.cppreference.com/w/cpp/language/if

More doc here: https://blog.tartanllama.xyz/if-constexpr/

Example here:

struct LeftSide
{
    static constexpr bool mIsLeft=true;
};

struct RightSide
{
    static constexpr bool mIsLeft=false;
};

template<typename Side>
int GetSide(std::pair<int, int> i)
{
    if constexpr (Side::mIsLeft)
        return i.first;
    else
        return i.second;
}

int main()
{
    std::cout<<GetSide<LeftSide>({1,2})<<std::endl;
    std::cout<<GetSide<RightSide>({3,4})<<std::endl;    
    return 0;
}

Output:

1

4

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM