选择方法作为(默认)模板参数

时间:2016-04-14 13:49:35

标签: c++ templates

我正在开发一个容器模板类。此代码需要与现有C代码接口,并且需要保持二进制兼容,因此我不能使用ie std::vector或类似代码。

我遇到的问题是它需要支持不同的分配策略,而且我不知道如何将分配器作为模板参数提供。我创建了一个SSCCE来说明我得到了多远(当然没有编译,因为如果可以的话,我不需要问这个问题:)。

#include <iostream>
#include <cstring>
#include <type_traits>

typedef unsigned int        uint_t;
typedef signed int          int_t;

template <typename T, typename S, typename _allocator = _virtual>
class Container
{
public:
    Container(S nItems = 0, S nMaxItems = 0, T *pArray = NULL)
    {
        mItems = nItems;
        mMaxItems = nMaxItems;
        mArray = pArray;
    }

    void adjustMalloc(uint_t nClusterSize)
    {
        if(mItems == mMaxItems)
        {
            mArray = (T *)realloc(mArray, (mMaxItems+nClusterSize)*sizeof(T));
            mMaxItems += nClusterSize;
        }
    }

    void adjustAligned(uint_t nClusterSize)
    {
        if(mItems == mMaxItems)
        {
            mArray = (T *)_aligned_realloc(mArray, (mMaxItems+nClusterSize)*sizeof(T), 16);
            mMaxItems += nClusterSize;
        }
    }

    void adjustVirtual(uint_t nClusterSize)
    {
        if(mItems == mMaxItems)
        {
            mArray = VirtualAlloc(mArray, (mMaxItems+nClusterSize)*sizeof(T), MEM_RESERVE, PAGE_NOACCESS);
            mMaxItems += nClusterSize;
        }
    }

    void adjust(uint_t nClusterSize)
    {
        if (std::is_same<_allocator>::value == _virtual)
            adjustVirtual(nClusterSize);
        else if(std::is_same<_allocator>::value == _aligned)
            adjustAligned(nClusterSize);
        else if(std::is_same<_allocator>::value == _malloc)
            adjustMalloc(nClusterSize);
        else
        {
            // Cause a static compiler error, how?
        }
    }

    bool add(T *pItem)
    {
        if(find(pItem) == NULL)
        {
            adjust(100);
            mItems++;

            return true;    // added
        }

        return false;
    }

    T *find(T *pItem)
    {
        T *p = mArray;

        for(S i = 0; i < mItems; i++, p++)
        {
            if(*p == *pItem)
                return p;
        }

        return NULL;
    }

private:
    S mItems;
    S mMaxItems;
    T *mArray;
};


class Record
{
public:

    bool operator==(const Record &oRecord)
    {
        if(Id != oRecord.Id)
            return false;

        if(strcmp(Name, oRecord.Name) != 0)
            return false;

        return true;
    }

    int Id;
    char Name[10+1];
};

int main(int argc, char *argv[])
{
    Record rec;
    rec.Id = 0;
    strcpy(rec.Name, "Test");

    Container<Record, uint_t> records;   // Default using malloc
    records.add(&rec);

    if(records.find(&rec) == NULL)
        std::cerr << "Not found" << std::endl;

    Container<Record, uint_t, _virtual> vrecords;   // VirtualAlloc allocator used.
    vrecords.add(&rec);

    if(records.find(&rec) == NULL)
        std::cerr << "Not found" << std::endl;

    return 0;
}

我使用的是Visual Studio 2010,因此它不是100%C ++ 11。

VirtualAlloc仅作为(另一个)示例提供,并且无法在此处显示。

1 个答案:

答案 0 :(得分:-1)

我找到了解决问题的方法。但是,我收到了警告

warning C4127: conditional expression is constant

adjust() if(std::is_same...方法中,我想知道这是否正常,或者我是否可以摆脱它,除了禁用它。

#include "stdafx.h"
#include "windows.h"

#include <iostream>
#include <cstring>
#include <type_traits>

#pragma warning (push)
//#pragma warning (disable : 4127)

typedef unsigned int        uint_t;
typedef signed int          int_t;

typedef struct { const static bool _virtual_allocator = true; } _virtual_type;
typedef struct { const static bool _aligned_allocator = true; } _aligned_type;
typedef struct { const static bool _malloc_allocator = true; } _malloc_type;

template <typename T, typename S, typename _allocator = _aligned_type>
class Container
{
public:
    Container(S nItems = 0, S nMaxItems = 0, T *pArray = NULL)
    {
        mItems = nItems;
        mMaxItems = nMaxItems;
        mArray = pArray;
    }

    void adjustMalloc(uint_t nClusterSize)
    {
        if(mItems == mMaxItems)
        {
            mArray = (T *)realloc(mArray, (mMaxItems+nClusterSize)*sizeof(T));
            mMaxItems += nClusterSize;
        }
    }

    void adjustAligned(uint_t nClusterSize)
    {
        if(mItems == mMaxItems)
        {
            mArray = (T *)_aligned_realloc(mArray, (mMaxItems+nClusterSize)*sizeof(T), 16);
            mMaxItems += nClusterSize;
        }
    }

    void adjustVirtual(uint_t nClusterSize)
    {
        if(mItems == mMaxItems)
        {
            mArray = (T *)VirtualAlloc((LPVOID)mArray, (mMaxItems+nClusterSize)*sizeof(T), MEM_RESERVE, PAGE_NOACCESS);
            mMaxItems += nClusterSize;
        }
    }

    void adjust(uint_t nClusterSize)
    {
        if (std::is_same<_allocator, _virtual_type>::value)
            adjustVirtual(nClusterSize);
        else if(std::is_same<_allocator, _aligned_type>::value)
            adjustAligned(nClusterSize);
        else if(std::is_same<_allocator, _malloc_type>::value)
            adjustMalloc(nClusterSize);
        else
        {
            // Cause a static compiler error, how?
        }
    }

    bool add(T *pItem)
    {
        if(find(pItem) == NULL)
        {
            adjust(100);
            mItems++;

            return true;    // added
        }

        return false;
    }

    T *find(T *pItem)
    {
        T *p = mArray;

        for(S i = 0; i < mItems; i++, p++)
        {
            if(*p == *pItem)
                return p;
        }

        return NULL;
    }

private:
    S mItems;
    S mMaxItems;
    T *mArray;
};

#pragma warning (pop)

class Record
{
public:
    bool operator==(const Record &oRecord)
    {
        if(Id != oRecord.Id)
            return false;

        if(strcmp(Name, oRecord.Name) != 0)
            return false;

        return true;
    }

    int Id;
    char Name[10+1];
};

int main(int argc, char *argv[])
{
    Record rec;
    rec.Id = 0;
    strcpy(rec.Name, "Test");

    Container<Record, uint_t> mrecords;
    mrecords.add(&rec);

    if(mrecords.find(&rec) == NULL)
        std::cerr << "Malloc Not found" << std::endl;

    Container<Record, uint_t, _aligned_type> arecords;
    arecords.add(&rec);

    if(arecords.find(&rec) == NULL)
        std::cerr << "Aligned Not found" << std::endl;

    Container<Record, uint_t, _virtual_type> vrecords;
    vrecords.add(&rec);

    if(vrecords.find(&rec) == NULL)
        std::cerr << "Virtual Not found" << std::endl;

    return 0;
}