Yebangyu's Blog

Fond of Concurrency Programming and Machine Learning

虚函数和变长参数模板的妙用

假如我们需要设计和实现自己的容器,比如说vector,list,queue等。

同一类容器,我们可能有不同的实现和用途,因此我们抽象出了一个Base Class,比如说(以Vector为例):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<iostream>
using namespace std;
template<typename T>
class BaseVector
{
public:
  virtual void pre_allocate(int capacity) = 0;
};

template<typename T>
class SmallVector: public BaseVector<T> //一种特定的实现
{
public:
  virtual void pre_allocate(int capacity)
  {
    p_ = (T*)malloc(sizeof(T) * capacity); //实际里可能不是malloc,而是自己实现的allocator
   //错误处理等等不在本文考虑范围之内
    for (int i = 0; i < capacity; ++i) {
      new(&p_[i]) T(); //预先构造好。注意,这里需要参数个数为0的默认构造函数
    }
  }
private:
  T *p_;
};
class NoParameters
{
  //do something
};
int main()
{
  SmallVector<NoParameters> vec0;
  vec0.pre_allocate(1000);
  return 0;
}

没问题。一切完美。不过你试图这样使用vector类,就不行了:

1
2
3
4
5
6
7
8
9
10
class OneParameter
{
public:
  OneParameter(int a)
  {
    //do something
  }
};
SmallVector<OneParameter> vec1;
vec1.pre_allocate(1000);

编译不过,因为以上实现要求函数参数列表为空的默认构造函数,而OneParameter类(只)提供了带一个参数的构造函数,因此编译出问题,如下所示。

1
2
3
4
../src/hehe.cpp:15:19: error: no matching constructor for initialization of 'OneParameter'
      new(&p_[i]) T();
1 error generated.
make: *** [src/hehe.o] Error 1

怎么办?使用C++11的变长参数模板,我们可以这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include<iostream>
using namespace std;
template<typename T, class... Args>
class BaseVector
{
public:
  virtual void pre_allocate(int capacity, Args...) = 0;
};
template<typename T, class... Args>
class SmallVector: public BaseVector<T, Args...>
{
public:
  virtual void pre_allocate(int capacity, Args... args)
  {
    cout<<"small vector"<<endl;
    p_ = (T*)malloc(sizeof(T) * capacity);
    for (int i = 0; i < capacity; ++i) {
      new(&p_[i]) T(std::forward<Args>(args)...);
    }
  }
private:
  T *p_;
};
template<typename T, class... Args>
class FastVector: public BaseVector<T, Args...>
{
public:
  virtual void pre_allocate(int capacity, Args... args)
  {
    cout<<"fast vector"<<endl;
    p_ = (T*)malloc(sizeof(T) * capacity);
    for (int i = 0; i < capacity; ++i) {
      new(&p_[i]) T(std::forward<Args>(args)...);
    }
  }
private:
  T *p_;
};
class TwoParameters
{
public:
  TwoParameters(int a, int b)
  {
    //do something
  }
};
class ThreeParameters
{
public:
  ThreeParameters(int a, int b, double c)
  {
    //do something
  }
};
int main()
{
  SmallVector<TwoParameters, int , int> small_vec2;
  SmallVector<ThreeParameters, int , int, double> small_vec3;
  FastVector<TwoParameters, int , int> fast_vec2;
  FastVector<ThreeParameters, int , int, double> fast_vec3;
  ////////////////////////////////////////////////////////
  BaseVector<TwoParameters, int , int> *p = &small_vec2;
  p->pre_allocate(1,1,1);
  p = &fast_vec2;
  p->pre_allocate(1,1,1);
  //////////////
  BaseVector<ThreeParameters, int , int, double> *q = &small_vec3;
  q->pre_allocate(1,2,2,2);
  q = &fast_vec3;
  q->pre_allocate(1,2,2,2);
  return 0;
}

输出如下:

1
2
3
4
small vector
fast vector
small vector
fast vector

啊,看起来多么完美!!!