专业编程基础技术教程

网站首页 > 基础教程 正文

C++模板 - 11(模板的模板参数)(c++模板的用法)

ccvgpt 2024-08-03 12:31:49 基础教程 13 ℃

前面介绍了类模板和函数模板,它们的模板参数可以是类型,也可以是非类型。其实模板参数还可以是第三种形式,即这个模板参数是一个类模板。不过这个仅对类模板适用,函数模板不支持。它的正式名字叫模板的模板参数(template template parameters),是不是听起来有点绕嘴?

看个例子,还是熟悉的Stack类模板

C++模板 - 11(模板的模板参数)(c++模板的用法)

template<typename T>
class Stack {
    T elems[100];
};

Stack使用数组作为内部存储。这个可能对用户来说是个限制,我们可以让用户来指定数据容器。

template<typename T, typename Cont = std::vector<T>>
class Stack {
    Cont elems;
};

这次我们添加了第二个模板参数,其缺省值为std::vector<T>。不过这个定义感觉有点不太准确,因为第二个模板参数的类型其实是有限定的,虽然我们用了Cont来告诉使用者需要使用一个容器类,但这个其实并没有任何约束力,你可以用任何类型来实例化Cont,当然编译是通不过的。我们改用模板的模板参数来强调这个约束。

template<typename T, template<typename ElemType> class Cont = std::vector>
class Stack {
    Cont<T> elems;
};

注意一下这次的定义和上面的区别,这次Cont不仅仅是个类型,它必须是个类模板,是有一个模板参数的类模板,这次Cont缺省值是std::vector。其实Cont里面的ElemType这个模板参数名称没有用处,可以省略,不过给它一个可读性强的名称会起来很好的说明作用。

不好意思,其实上面这个定义并不准确,在C++17之前甚至还是错误的,编译通不过。原因是std::vector这个类模板的模板参数是两个(虽然第二个模板参数定义了缺省值),上面的定义中第二个模板参数是有着一个模板参数的类模板(C++17之后编译器会考虑缺省的模板参数,编译可以通过了)。

template<
    class T,
    class Allocator = std::allocator<T>
> class vector

我觉得模板的模板参数最大的用途是用在“类型函数”的定义中。什么是类型函数?我们把之前的函数称为值函数:函数的输入参数是值,函数的返回结果也是值。换个角度来看类模板,它可以称为类型函数:模板参数是类型,通过定义类型成员来作为返回结果。

template<typename T>
struct AddRef{
    using Type = T&; 
};

template<typename T>
struct AddRef<T&>{
    using Type = T&;
};

template<>
struct AddRef<void>{
    using Type = void;
};

我们定义了一个类型函数(类模板),对于模板参数T,其返回类型Type为T&。后面我们定义了一个部分特化(处理模板参数本身是引用的类型,我们让它返回类型本身。我可不想应付引用的引用这一让人头大的东西)和一个完全特化(void类型可没法引用哦)。

好了,开始进入我们的重点。如果函数的参数类型中也有函数的话,我们称它为高阶函数。那类模板的模板参数本身也是个类模板的话,可以称为“高阶类型函数”。

template<typename T, template<typename> class TypeTrans>
struct Transform{
    using Type = typename TypeTrans<T>::Type;
};

Transform类模板的功能也是给模板参数T返回一个转换后的类型,但是这次的转换方式是由第二个模板参数TypeTrans来完成的。这样将来如果你要给T添加指针,你只需要定义一个AddPointer类模板,然后用作它的第二个参数就行了。

Tags:

最近发表
标签列表