When recursing over a parameter pack, given the choice, should I prefer to recurse via inheritance, or via a member field (composition)? Is this a cut-and-dried matter? What are the trade-offs?
One thing that I'm wondering, for example, is whether the composition-based form is generally considered to have better compilation speed, memory usage, or error reporting.
To illustrate, the following is an example of short-circuit or_
(disjunction) inspired by Jonathan Wakely's answer here.
Inheritance-based:
#include <type_traits>
// disjunction
template<typename... Conds>
struct or_ : std::false_type {};
template<typename Cond, typename... Conds>
struct or_<Cond, Conds...>
: std::conditional<Cond::value, std::true_type, or_<Conds...>>::type
{};
static_assert(or_<std::true_type, std::true_type, std::true_type>::value,"");
static_assert(or_<std::false_type, std::false_type, std::true_type>::value,"");
static_assert(or_<std::false_type, std::false_type, std::false_type>::value == false,"");
I understand that this version has the feature that or_<Ts...>
will inherit from std::integral_constant
. Please assume for the sake of my question that I don't care about whether or_
inherits from an integral_constant
.
Composition-based:
template<typename... Conds>
struct or_ {
static constexpr bool value = false;
};
template<typename Cond, typename... Conds>
struct or_<Cond, Conds...> {
static constexpr bool value = std::conditional<Cond::value, std::true_type, or_<Conds...>>::type::value;
};
This form seems intuitively better to me, because the value is always located in the type itself, not in some superclass, but I'm not sure whether this is generally considered preferable.
P.S. I know that in C++17 I could often use fold expressions. But I'm aiming for C++11 compatibility.