使用模板有条件地生成C ++类的数据成员

时间:2015-08-10 14:53:31

标签: c++ templates c++11

我有一个类在一些固定范围内作为一组整数工作 0 ... n并且可以轻松处理添加新元素,删除元素,清空集合以及检查整数是否是集合的一部分。遵循该类的代码。

此外,从代码中可以看出,如果选项COMPUTE_SET_SIZE存在,则类计算集合的大小,如果存在选项COMPUTE_LINKED_LIST,则可以有效地使用该类枚举集合元素。

现在,问题在于枚举集合元素在内存使用方面是一项繁重的操作,并且在很多时候,不需要它。因此,我希望能够以某种方式仅在需要时生成代码的这些部分,而不必维护两个不同的类(一个具有此功能而另一个没有)。

我知道模板(例如std :: enable_if)可以用来实现类似的目标,但我无法理解如何使用它们有条件地生成数据成员,例如以下代码中的prev和next。

#ifndef _FIXED_SIZE_INT_SET_H_
#define _FIXED_SIZE_INT_SET_H_

#include <cstring>

#include <assert.h>

#define COMPUTE_SET_SIZE
#define COMPUTE_LINKED_LIST

class FixedSizeIntSet
{
    private:
        const int MAX_TAG = 1000000000;
        int capacity;
        int currentTag;
        int *tags;

#ifdef COMPUTE_SET_SIZE
        int size;
#endif

#ifdef COMPUTE_LINKED_LIST
        int start;
        int *next;
        int *prev;
#endif

        void initialize() { memset(tags, 0, capacity * sizeof(int)); }
    public:
        FixedSizeIntSet(int capacity)
        {
            this->capacity = capacity;
            this->currentTag = 1;
            tags = new int[capacity];

#ifdef COMPUTE_SET_SIZE
            size = 0;
#endif

#ifdef COMPUTE_LINKED_LIST
            start = -1;
            next = new int[capacity];
            prev = new int[capacity];
#endif

            initialize();
        }

        void insert(int n)
        {
            assert((n >= 0) && (n < capacity));
#ifdef COMPUTE_SET_SIZE
            if (tags[n] != currentTag) size++;
#endif
#ifdef COMPUTE_LINKED_LIST
            if (tags[n] != currentTag)
            {
                next[n] = start;
                prev[n] = -1;
                if (start >= 0)
                    prev[start] = n;
                start = n;
            }
#endif
            tags[n] = currentTag;
        }
        void remove(int n)
        {
            if ((n >= 0) && (n < capacity))
            {
#ifdef COMPUTE_SET_SIZE
                if (tags[n] == currentTag) size--;
#endif
#ifdef COMPUTE_LINKED_LIST
                if (tags[n] == currentTag)
                {
                    if (next[n] >= 0)
                        prev[next[n]] = prev[n];
                    if (prev[n] >= 0)
                        next[prev[n]] = next[n];
                    else
                        start = next[n];
                }
#endif
                tags[n] = 0;
            }
        }
        void clear()
        {
            if (currentTag < MAX_TAG)
                currentTag++;
            else { initialize(); currentTag = 1; }
#ifdef COMPUTE_SET_SIZE
            size = 0;
#endif
#ifdef COMPUTE_LINKED_LIST
            start = -1;
#endif
        }

        bool hasMember(int n) { return ((n >= 0) && (n < capacity)) ? (currentTag == tags[n]) : false; }

#ifdef COMPUTE_LINKED_LIST
        int begin() { return start; }
        int end() { return -1; }
        int nextNumber(int curNumber) { assert((curNumber >= 0) && (curNumber < capacity)); return next[curNumber]; }
#endif
};

#endif

理想情况下,我想要一个像这样的代码:

template <bool enableEnumeration>
class FixedSizeIntSet {
  ....
}

FixedSizeIntSet<false>计算链接列表时,FixedSizeIntSet<true>不计算链表(并且没有关联的数据成员)。

1 个答案:

答案 0 :(得分:2)

这是解决您的设计问题的一种方法。

班级的定义。

#ifndef _FIXED_SIZE_INT_SET_H_
#define _FIXED_SIZE_INT_SET_H_

#include <cstring>

#include <assert.h>

template <typename Trait>
class FixedSizeIntSet : public Trait
{
    private:
        const int MAX_TAG = 1000000000;
        int capacity;
        int currentTag;
        int *tags;

        void initialize() { memset(tags, 0, capacity * sizeof(int)); }
    public:
        FixedSizeIntSet(int capacity) : Trait(capacity)
        {
            this->capacity = capacity;
            this->currentTag = 1;
            tags = new int[capacity];
            initialize();
        }

        void insert(int n)
        {
            assert((n >= 0) && (n < capacity));
            if (tags[n] != currentTag)
            {
               Trait::insert();
            }
            tags[n] = currentTag;
        }
        void remove(int n)
        {
            if ((n >= 0) && (n < capacity))
            {
                if (tags[n] == currentTag) 
                {
                   Trait::remove(n);
                }
                tags[n] = 0;
            }
        }
        void clear()
        {
            if (currentTag < MAX_TAG)
                currentTag++;
            else { initialize(); currentTag = 1; }
            Trait::clear();
        }

        bool hasMember(int n) { return ((n >= 0) && (n < capacity)) ? (currentTag == tags[n]) : false; }
};

#endif

用法:

struct ComputeSetSize
{
   ComputeSetSize(int ) : size(0) {}
   void insert(int ) { ++size; }
   void remove(int ) { --size; }
   void clear() { size = 0; }
   int size;
};

struct ComputeLinkedList
{
   ComputeLinkedList(int capacity)
   {
      start = -1;
      next = new int[capacity];
      prev = new int[capacity];
   }

   void insert(int n)
   {
      next[n] = start;
      prev[n] = -1;
      if (start >= 0)
         prev[start] = n;
      start = n;
   }

   void remove(int n)
   {
      if (next[n] >= 0)
         prev[next[n]] = prev[n];
      if (prev[n] >= 0)
         next[prev[n]] = next[n];
      else
         start = next[n];
   }

   void clear()
   {
      start = -1;
   }

   int begin() { return start; }
   int end() { return -1; }
   int nextNumber(int curNumber) { assert((curNumber >= 0) && (curNumber < capacity)); return next[curNumber]; }

   int capacity;
   int size;
   int start;
   int *next;
   int *prev;
};


int main()
{
   FixedSizeIntSet<ComputeSetSize> set1(10);
   FixedSizeIntSet<ComputeLinkedList> set2(20);
}