嵌套在模板化类中的类的大小,但不依赖于模板参数

时间:2014-12-27 22:58:36

标签: c++ templates sizeof

我有以下代码:

template < unsigned int Num, class ValueType >

class COuter
{

    public:     
    class CInner
    {

        private:
        CInner* m_pPrev;
        CInner* m_pNext;
        ValueType*  m_pValue;
    }
}

CInner的大小显然不依赖于COuter的模板参数

有办法吗

sizeof(COuter::CInner) 

无需为COuter指定模板参数?

谢谢!

2 个答案:

答案 0 :(得分:1)

如果使用这些指针时的类型安全是您主要关注的问题,那么您可以这样做:

class CInnerBase
{
    protected:
    void* m_pPrev;
    void* m_pNext;
    void* m_pValue;
};

template <unsigned int Num, class ValueType>
class COuter
{
    public:     
    class CInner : public CInnerBase
    {
        public:
        ValueType* pValue() { return static_cast<ValueType*>(m_pValue); }
        //and similar for m_pPrev and m_pNext
        //also type-safe constructors and assignment operators
    };
};

然后您的分配器可以使用CInnerBaseCOuter可以将从分配器获取的内容转换为适当的CInner*类型。

CInnerBase可以是分配器类的内部类。

您可能会发现某些不依赖于这些模板参数的功能会自然地从模板CInner迁移到非模板CInnerBase - 这对于避免代码膨胀也不错。

此外,如果有帮助,m_pPrevm_pNext可能是CInnerBase*

答案 1 :(得分:0)

您希望从同一内存池分配两个或多个具有相同布局但具有不同类型的对象。

假设您正在使用与此类似的内存池类模板:https://github.com/cacay/MemoryPool

template<typename T>
struct memory_pool
{
    T* allocate();
    void deallocate(T*);
};

在这种特定情况下,您可以使用void CInner的特化作为内存池的参数。这是有效的,因为它是一种POD类型,与CInner的任何其他专业化具有相同的大小和对齐要求。

typedef COuter<0, void>::CInner Storage;
typedef memory_pool<Storage> Pool;

然后,您可以使用以下分配和解除分配函数,这些函数使用placement new将POD存储类型转换为所需类型。

#include <new>

template<typename T>
T* allocate(Pool& pool)
{
    static_assert(sizeof(T) == sizeof(Storage));
    static_assert(alignof(T) == alignof(Storage));
    return new (pool.allocate()) T();
}

template<typename T>
void deallocate(Pool& pool, T* p)
{
    static_assert(sizeof(T) == sizeof(Storage));
    static_assert(alignof(T) == alignof(Storage));
    p->~T();
    pool.deallocate(reinterpret_cast<Storage*>(p));
}

int main()
{
    Pool pool;
    typedef COuter<0, int>::CInner Type;
    Type* p = allocate<Type>(pool);
    deallocate(pool, p);
}

如果您的编译器支持std::aligned_storage - C ++ 11功能 - 您可以更通用的方式定义Storage,这将允许CInner成为非POD类型:< / p>

#include <type_traits> 

typedef COuter<0, void>::CInner VoidInner;
const std::size_t SIZE = sizeof(VoidInner);
const std::size_t ALIGN = alignof(VoidInner);
typedef std::aligned_storage<SIZE, ALIGN>::type Storage;