Search code examples
c++stdc++17variadic-templatesif-constexpr

In what sense is std::disjunction short-circuiting at compile_time


From the description on cppreference.com, I was under the impression that std::disjunction is designed to give me short-circuiting at compile-time, so that I can use it like this:

#include <type_traits>
#include <iostream>

template<nullptr_t null = nullptr>
constexpr bool does_not_compile() {
    static_assert(null != nullptr);
    return false;
}

void hello_world () {
    if constexpr (std::disjunction_v<std::true_type, std::bool_constant<does_not_compile()>>) {
        std::cout << "Hello World!" << std::endl;
    }
}

However, this does not compile, std::disjunction does not short-circuit in the sense that the above static_assert doesn't trigger (live example).

But then it what sense is it short-circuiting? It can't be the usual behavior of || at run time, because the type of the std::disjunction has to be known at compile time, and it depends on its value.


Solution

  • You find an explanation right on the page you linked to:

    Disjunction is short-circuiting: if there is a template type argument Bi with bool(Bi::value) != false, then instantiating disjunction<B1, ..., BN>::value does not require the instantiation of Bj::value for j > i

    The short-circuiting behavior concerns the value member of each parameter type, not the parameter type itself. You cannot instantiate a template without knowing it's paramters. And using std::disjunction<…> will generally require an instantiation. In your example

    std::disjunction_v<std::true_type, std::bool_constant<does_not_compile()>>
    

    the compiler still has to instantiate std::bool_constant<does_not_compile()> so that it knows what the whole std::disjunction<…> comes out to be (as you have noted yourself). What is guaranteed is that it won't instantiate std::bool_constant<does_not_compile()>::value