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.
You find an explanation right on the page you linked to:
Disjunction is short-circuiting: if there is a template type argument
Bi
withbool(Bi::value) != false
, then instantiatingdisjunction<B1, ..., BN>::value
does not require the instantiation ofBj::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
…