template<class T>
T *MemNew(size_t count)
{
T *p = (T*)MemPool<T, count>::Allocate();
if (p != NULL)
{
if (!std::is_pod<T>::value)
{
for (size_t i = 0; i < count; ++i)
{
new (&p[i]) T();
}
}
}
return p;
}
template<class T>
T *MemDelete(T *p, size_t count)
{
if (p != NULL)
{
if (!std::is_pod<T>::value)
{
for (size_t i = 0; i < count; ++i)
{
p[i].~T();
}
}
MemPool<T, count>::DeAllocate(p);
}
}
上述实现中,使用placement new对申请的内存进行构造,使用了默认构造函数,当申请内存的类型不具备默认构造函数时,placement new将报错。对于pod类型,可以省去调用构造函数的过程。
引入C++11变长模板参数后MemNew修改为如下
template<class T, class... Args>
T *MemNew(size_t count, Args&&... args)
{
T *p = (T*)MemPool<T, count>::Allocate();
if (p != NULL)
{
if (!std::is_pod<T>::value)
{
for (size_t i = 0; i < count; ++i)
{
new (&p[i]) T(std::forward<Args>(args)...);
}
}
}
return p;
}
以上函数定义包含了多个特性,后面我将一一解释,其中class... Args 表示变长参数模板,函数参数中Args&& 为右值引用。std::forward<Args> 实现参数的完美转发。这样,无论传入的类型具有什么样的构造函数,都能够完美执行
C++11中引入了变长参数模板的概念,来解决参数个数不确定的模板。
template<class... T> class Test {};
Test<> test0;
Test<int> test1;
Test<int,int> test2;
Test<int,int,long> test3;
template<class... T> void test(T... args);
test();
test<int>(0);
test<int,int,long>(0,0,0L);
以上分别是使用变长参数类模板和变长参数函数模板的例子。
2.1变长参数函数模板
T... args 为形参包,其中args是模式,形参包中可以有0到任意多个参数。调用函数时,可以传任意多个实参。对于函数定义来说,该如何使用参数包呢?在上文的MemNew中,我们使用std::forward依次将参数包传入构造函数,并不关注每个参数具体是什么。如果需要,我们可以用sizeof...(args)操作获取参数个数,也可以把参数包展开,对每个参数做更多的事。展开的方法有两种,递归函数,逗号表达式。
递归函数方式展开,模板推导的时候,一层层递归展开,最后到没有参数时用定义的一般函数终止。
void test()
{
}
template<class T, class... Args>
void test(T first, Args... args)
{
std::cout << typeid(T).name() << " " << first << std::endl;
test(args...);
}
test<int, int, long>(0, 0, 0L);
output:
int 0
int 0
long 0










