vendredi 23 décembre 2016

Inheritance or composition when recursing over a parameter pack?

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.

Aucun commentaire:

Enregistrer un commentaire