themagicalyang
themagicalyang

Reputation: 2553

Does logical short-circuiting not work with if-constexpr?

With normal if condition, short circuiting works.

However with an attempted short circuit for if-constexpr doesn't work:

#include <iostream>
template <typename ... Args>
void foo(Args... args) {
    std::string a; 
    // for the call of foo, sizeof...(args) = 0, so a > 2 shouldn't be evaluated.
    if constexpr (sizeof...(args) == 0 || a > 2) {
        std::cout << "ASD" << '\n';
    }
}

int main() {
   foo();
}

Demo

Edit: Seems like lots of comments are bit off of what I was attempting. I will just quote @chris comment:

People seem to be missing the point, so here's a better example of why this is useful:

if constexpr (sizeof...(Ts) > 0 && is_integral_v<first_t<Ts...>>) { 
    /* corresponding logic */ 
}

Currently, this requires nested constexpr ifs

It seems this is not currently possible and only workaround is just write nested ifs.

Upvotes: 8

Views: 1304

Answers (3)

Harold
Harold

Reputation: 170

You can use short-circuit form in if constexpr, but please notice, this may performs differently with runtime if. Consider the following example:

godbolt

#include <type_traits>

template<typename T>
constexpr auto foo(T const& val)
{
    if constexpr (std::is_integral_v<T>)
    {
        if constexpr (T{} < 1)
            return val * 2;
    }
    return val;
}

template<typename T>
constexpr auto bar(T const& val)
{
    if constexpr (std::is_integral_v<T> && T{} < 1)
        return val * 2;
    else
        return val;
}

int main()
{
    constexpr char const* x = "hello";
    static_assert(foo(5) == 5 * 2);
    static_assert(foo(x) == x);

    static_assert(bar(5) == 5 * 2);
    //static_assert(bar(x) == x);  // ERROR, not compile

    return 0;
}

The foo will compile with both int and char const* while bar not, and because std::is_integral_v<T> && T{} < 1 in bar is instantiated as a whole.

So you'd better NOT short-circuit if constexpr to avoid this unexpected behavior.

Upvotes: 0

user743382
user743382

Reputation:

The expression a > 2 needs to be syntactically and semantically valid, because otherwise, the compiler cannot rule out that it would return some type for which the || operator is overloaded. Only the built-in || operator has short-circuiting behaviour.

However, the expression a > 2 would not be evaluated. You can verify this by changing std::string a to int a (left uninitialised): evaluation of the expression a > 2 would have undefined behaviour, and therefore evaluation of a > 2 is not permitted in constant expressions.

Upvotes: 5

Aurel B&#237;l&#253;
Aurel B&#237;l&#253;

Reputation: 7983

While the condition might not be evaluated, your program doesn't compile because it is invalid – you can't compare a string and an int. You would get similar results if you put random characters in the second operand of the ||.

Upvotes: 4

Related Questions