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

Using templates to conditionally generate data members of a C++ class

本文关键字:c++ 数据成员 有条件      更新时间:2023-10-16

我有一个类,它作为一组固定范围内的整数工作0…可以很容易地处理添加新元素、删除元素、清空集合以及检查整数是否属于集合的一部分。下面是类的代码。

同样,从代码中可以看出,如果选项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>计算链表

这里有一个方法来解决你的设计问题。

类定义。

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