Determining the largest derived class at compile time

Let's say I have a class Basethat has Nchildren, Derived0, Derived1, ... ,DerivedN. I am trying to create a pool allocator for objects that inherit from Base, and the implementation depends on knowing the size of the largest child Base, since each of them can be large enough to contain one of these objects. Here is a simple example with trivial classes and N = 2. Actually, there Ncan be more, and Basechildren can be more than just POD classes.

class Base {
public:
    virtual ~Base() = 0;
};

class Derived0 : public Base {
    int a;
};

class Derived1 : public Base {
    int a, b;
};

class Derived2 : public Base {
    int a, b, c;
};

So, let's say that I want to create a buffer large enough to hold 10 children. I banged my head several times about this, and that’s all I can think of:

static const size_t NUMBER_OF_POOLS = 10;

static const size_t LARGEST_CHILD_SIZE =
    sizeof(Derived0) > sizeof(Derived1) ?
        sizeof(Derived0) > sizeof(Derived2) ?
            sizeof(Derived0) :
            sizeof(Derived2) :
        sizeof(Derived1) > sizeof(Derived2) ?
            sizeof(Derived1) :
            sizeof(Derived2);

char buffer[NUMBER_OF_POOLS * LARGEST_CHILD_SIZE];

, , , N . - , " " (- ), , N ?

/, :

  • .
  • ++ 03 . (++ 11 welcome!) , ++ 11. , ++ 11 , POD, , .
  • GCC, GCC .

/ .

+4
3

boost::variant :

    sizeof (boost::variant< Derived0, Derived1, Derived2 > )  

.

, , . , :

    typedef boost::variant< Derived0, Derived1, Derived2 > DerivedVar; 
    DerivedVar buffer[NUMBER_OF_POOLS];  
+3

POD:

union AllDerived {
    Derived0 _0;
    Derived1 _1;
    Derived2 _2;
};

static const size_t LARGEST_CHILD_SIZE = sizeof(AllDerived);
static const size_t NUMBER_OF_POOLS = 10;
char buffer[NUMBER_OF_POOLS * LARGEST_CHILD_SIZE];

POD:

template <int Value1, int Value2>
struct static_max {
    static const int value = (Value1 < Value2) ? Value2 : Value1 ;
};

template<typename T, typename U>
struct TypeList {
    typedef T Head;
    typedef U Tail;
};

class NullType {};

template
<
    typename T1  = NullType, typename T2  = NullType, typename T3  = NullType,
    typename T4  = NullType, typename T5  = NullType, typename T6  = NullType,
    typename T7  = NullType, typename T8  = NullType, typename T9  = NullType,
    typename T10 = NullType, typename T11 = NullType, typename T12 = NullType,
    typename T13 = NullType, typename T14 = NullType, typename T15 = NullType,
    typename T16 = NullType, typename T17 = NullType, typename T18 = NullType
>
struct MakeTypelist
{
private:
    typedef typename MakeTypelist
    <
        T2 , T3 , T4 ,
        T5 , T6 , T7 ,
        T8 , T9 , T10,
        T11, T12, T13,
        T14, T15, T16,
        T17, T18
    >
    ::Result TailResult;

public:
    typedef TypeList<T1, TailResult> Result;
};

template<>
struct MakeTypelist<>
{
    typedef NullType Result;
};

template<typename TList>
struct MaxTypeSize;

template <>
struct MaxTypeSize<NullType> {
    enum { value=0 };
};

template<typename T, typename U>
struct MaxTypeSize<TypeList<T,U>> {
    enum { value = static_max<sizeof(T), MaxTypeSize<U>::value>::value };
};

typedef MakeTypelist<Derived0, Derived1, Derived2>::Result AllTypes;
static const size_t LARGEST_CHILD_SIZE = MaxTypeSize<AllTypes>::value;
static const size_t NUMBER_OF_POOLS = 10;
char buffer[NUMBER_OF_POOLS * LARGEST_CHILD_SIZE];

type list compile-type max. Loki. MaxTypeSize .

+3

, , . , STATIC_MAX(sizeof(... ). ++ 03.

#define STATIC_MAX(a, b)  ((a) > (b) ? (a) : (b))

static const size_t LARGEST_CHILD_SIZE =
    STATIC_MAX(sizeof(Derived0),
    STATIC_MAX(sizeof(Derived1),
    STATIC_MAX(sizeof(Derived2),
               0)));

And if the C ++ 1x compiler is an option, you can use the "variadic template" and the "constexpr function" to get a simpler solution. When a new derived class is added, simply insert the class name as the template parameter on the last line.

template <typename T>
static constexpr T static_max(T a, T b) {
    return a < b ? b : a;
}

template <typename T, typename... Ts>
static constexpr T static_max(T a, Ts... bs) {
    return static_max(a, static_max(bs...));
}

template <typename... Ts>
constexpr size_t max_sizeof() {
    return static_max(sizeof(Ts)...);
};

static constexpr size_t LARGEST_CHILD_SIZE =
    max_sizeof<Derived0, Derived1, Derived2>();
+1
source

All Articles