I have a compile-time condition, using std::conditional<cond, TypeA, TypeB>
. In my case, the condition is a disjunction, along the lines of SimpleCondition<T>::value || ComplexCondition<T>::value
. In my case T is a list of length n, and I can show that SimpleCondition<T>::value
can be processed in O(1) time, while ComplexCondition<T>::Value
requires O(n) time. I would like to rely on shortcutting to ensure I don't compute the O(n) side every single time... assuming I can.
If these were runtime functions instead of compile time constants, it would be easy to show that simpleCondition(t) || complexCondition(t)
will shortcut. Is shortcutting guaranteed for compile time constants too?
As a more extreme case, consider the case where SimpleCondition is being used to work around the halting problem. Perhaps ComplexCondition<T>::value
can be proven to terminate for many values, but that proof is unavailable for cases where SimpleCondition<T>::value
is true. In such a circumstance, this question of shortcutting would be the difference between a program that provably compiles and one that does not.
When evaluating SimpleCondition<T>::value || ComplexCondition<T>::value
the compiler looks up and instantiates SimpleCondition<T>
and ComplexCondition<T>
and then looks up the value
member. The instantiation is what actually does any compile time evaluation, so while the eventual (assuming they both are true
) true || true
would "short circuit", no extra work would need to be done at that point.
The solution is to use std::disjunction
.
std::disjunction_v<SimpleCondition<T>, ComplexCondition<T>>
gives essentially the same result, but will not instantiate ComplexCondition<T>
if SimpleCondition<T>::value
is true
. This means if ComplexCondition<T>
would have an error (e.g., an infinite recursion), or it would just take a lot of compile time resources to compute, they just won't happen.
(And std::conjunction_v
for the &&
case)