我们说我有一个班级Base
,其中有N
个孩子,Derived0, Derived1, ... ,DerivedN
。我正在尝试为从Base
继承的对象创建池分配器,并且实现依赖于知道Base
的最大子节点的大小,因为每个池都足够大以包含其中一个对象。这是一个简单的例子,包含普通的类和N = 2
。实际上,N
可能会更大,Base
的孩子可能不是简单的POD课程。
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;
};
所以,让我们说我想创建一个足够大的缓冲区来存储10个孩子。我已经在这上面敲了一会儿,这就是我能想到的:
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
的增加而变成一个巨大的混乱?
以下是我正在使用的约束/环境:
任何帮助/建议表示赞赏。
答案 0 :(得分:3)
您可以考虑使用boost::variant
并使用其大小:
sizeof (boost::variant< Derived0, Derived1, Derived2 > )
这将返回最大元素的大小。
顺便说一句,它还可以简化缓冲区管理,使其成为此变体的缓冲区,并直接索引正确的元素。好消息是,提升需要考虑对齐要求:
typedef boost::variant< Derived0, Derived1, Derived2 > DerivedVar;
DerivedVar buffer[NUMBER_OF_POOLS];
答案 1 :(得分: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];
这里我们使用类型列表和编译类型的最大函数。您可以在Loki库中找到类型列表实现。编译时函数MaxTypeSize计算列表中的最大类型大小。
答案 2 :(得分:1)
通过引入辅助宏来修改代码,从而产生更好的代码格式。添加新的派生类后,只需插入STATIC_MAX(sizeof(...
行并添加)
即可。这适用于C ++ 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)));
如果C ++ 1x编译器是一个选项,您可以使用“variadic template”和“constexpr function”来获得更简单的解决方案。添加新的派生类时,只需在最后一行插入类名作为模板参数。
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>();