Select a method as (default) template parameter

Devolus

I'm developing a container template class. This code needs to interface with existing C code and needs to stay binary compatible, so I can not use i.e. std::vector or similar.

The problem that I have is that it needs to support different allocation strategies, and I don't know how to provide the allocator as a template argument. I created an SSCCE to illustrate how far I got (which of course doesn't compile, because if it would, I wouldn't need to ask this question :)).

#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;
}

I'm using Visual Studio 2010 so it's not 100% C++11.

The VirtualAlloc is provided just as (another) example and will not work as it is shown here.

Devolus

I found a solution for my problem. However, I get warnings

warning C4127: conditional expression is constant

in the adjust() method for the if(std::is_same... and I was wondering if this is normal or if I can get rid of it, other than disabling it.

#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;
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Can a template template parameter default reference other template type parameters?

Passing a COM method default parameter

Parameter pack with default template argument

Is default template template parameter value deduced context?

Overriding trait method with default parameter

Template template parameter and default values

kotlin overload method with default parameter

template class default float parameter

Calling a template method on a class template parameter

Default template parameter with class

Template argument deduction failed with default template parameter

Default template parameter based on type of other template parameter

Non-type template parameter dependent on a default template type parameter

Template parameter list with default class

template method "=0" in the parameter list

Default argument parameter in template specialization

Default template parameter with a default value?

ostream default parameter in template function

Add method to class by template parameter

Deducing template parameter from default parameter

Default template argument in method hidden behind class default template argument

Template function default parameter

Default parameter in template -> template argument involves template parameter

moq a method with a template parameter

Template class with method depending on template parameter

Fully specialized overloaded method is not called when used as template default parameter

Select as a method parameter

Default template parameter cannot be used inside another template parameter?

Is "this" a default parameter in a class method?