C++泛型编码的理解
1.指针的算术运算
假设我们要完成一下工作。给定一个储存整数的vector,以及一个整数值,如果此值存在于vector内,我们必须返回一个指针指向该值;反之则返回0,表示此值不在vector内。以下便是我的做法:
const int *find(const vector<int> &vec, int value)
{
for (int i = 0; i < vec.size(); ++i)
{
if (vec[i] == value)
return &vec[i];
}
return 0;
}
测试这个函数,发现其结果的确满足我们的需求,但是我们又获得一个新人物:想办法让这个函数不仅可以处理整数,更可以处理任何类型--前提是该类型定义有equality(相等)运算符。此时,我们可以运用function template的形式呈现:
template <typename elemType>
const elemType* find(const vector<elemType> &vec,
const elemType &value)
{
for (int i = 0; i < vec.size(); i++)
{
if (vec[i] == value)
return &vec[i];
}
return 0;
}
再次测试这个函数,其执行结果同样符合我们的需求。继续下一个任务,便是让这个函数同时可以处理vector与array内的任意类型元素--当然该类型的equality运算符依旧已定义。首先映入脑海的想法便是函数重载(overload),一份用来处理vector,另一份用来处理array。
//处理vector的版本
template <typename elemType>
const elemType* find(const vector<elemType> &vec,
const elemType &value)
{
for (int i = 0; i < vec.size(); i++)
{
if (vec[i] == value)
return &vec[i];
}
return 0;
}
//处理array的版本
template <typename elemType, size_t n>
const elemType* find(const array<elemType, n> &arr,
const elemType &value)
{
for (int i = 0; i < arr.size(); i++)
{
if (arr[i] == value)
return &arr[i];
}
return 0;
}
测试重载版本,发现其结果也同样满足我们的需求,但是重复编写两份逻辑类似的代码似乎有点多此一举。有一种存在已久的对策,就是将问题分割为数个较小、相对简单的子问题。本例中我们的大问题可以切割为:(1)将array的元素传入find(),而不指明该array,(2)将vector的元素传入find(),而非指明该vector。
首先解决array的处理问题。如何才能够在不指定array的情形下将其元素传入find()呢?我们可以回想一下C语言中如何传参数组。当我们写下:
int min(int array[24]) { ... }
min()似乎仅能接受某个拥有24个元素的array,并且以值的方式传入。事实上,这两个假设都是错误的:array并不会以传值方式复制一份,而且我们可以传递任意大小的array给min()。
当数组被传给函数,或是由函数中返回,仅有第一个元素的地址会被传递。一下的min()函数声明就精确多了:
int min(int *array) { ... }
min()可接受任意大小:1, 32, 1024, 等等,此时这迫使我们必须为不同大小的array编写其专属的min()函数。
指向array开头的指针,使我们得以开始对array进行读取操作。接下来我们必须设法告诉min(),应该在何处停止对array的读取。解法之一是:增加一个参数,用来表示array的大小。如下:
template <typename elemType>
const elemType* find(const elemType *array, int size,
const elemType &value)
{
if (!array || size < 1)
return nullptr;
for(int i = 0; i < size; i++)
{
if (value == array[i])
return &array[i];
}
return nullptr;
}
解法之二则是传入另一个地址,指示array读取操作的重点。
template <typename elemType>
const elemType* find(const elemType *first, const elemType *last,
const elemType &value)
{
if (!first || !last)
return 0;
for (; first != last; ++first)
if (*first == value)
return first;
return 0;
}
这种解法使得array从参数列表中彻底消失了--解决了我们的前面提到的第一个小问题。