C++ Template 基础篇(三):参数魔法

来源:互联网 发布:如何理财 知乎 编辑:程序博客网 时间:2024/05/16 08:14

Template 基础篇-参数魔法

Template所代表的泛型编程是C++语言中的重要的组成部分,我将通过几篇blog对这半年以来的学习做一个系统的总结,本文是基础篇的第三部分。

  • Template 基础篇-参数魔法
    • 默认实参
    • 模板的模板参数
    • 非类型参数

除了使用类型作为模板的参数之外,模板参数有更多的用法,以下做个详细介绍。

默认实参

我们可以通过给模板指定默认实参,为用户推荐合适的默认设定,让用户在只指定部分(或完全不指定)实参的情况下使用模板。

注意:模板的默认实参与函数的默认实参一样,必须从右向左定义。

在C++98中,只能为类模板指定默认实参。

template<typename T = int, typename U> //error, 必须从右向左struct Wrapper1 {      T t;};template<typename T, typename U = int> //okstruct Wrapper2 {    T t;};Wrapper2<double> w;template<typename T = int>struct Wrapper3 {    T t;};Wrapper3<> w; //w的类型为Wrapper<int>,注意空的<>必须写上

在C++11中,还可以为函数模板指定默认实参

template<typename T, typename F = std::less<T>> //指定F的默认值是std::less<T>int compare(const T& left, const T& right, F f = F()) { //注意这里,std::less是一个functor    if (f(left, right)) {        return -1;    }    if (f(right, left)) {        return 1;    }    return 0;}compare(1, 2); //未指定第三个参数,使用默认值std::less<int>

模板的模板参数

除了内置类型(int float bool等)和自定义类型(class struct)可以作为模板实参之外,C++还允许使用一个模板作为另外一个模板的实参,这使得模板的用户可以对模板的行为进行深度的定制。例如:指定模板存储数据使用另外一种STL容器。

声明模板的模板参数时,必须使用template和class关键字,必须使用另外一个模板的完整声明。

template<typename T,          template<typename ELEM> typename CONT> //error,必须使用class关键字class ContainerWrapper {public:    CONT<T> elems;};template<typename T,          template<typename ELEM> class CONT> //okclass ContainerWrapper {public:    CONT<T> elems;};ContainerWrapper<int, std::deque> cw; //error,std::deque不匹配//std::deque中除了ELEM之外还有一个有默认值的Alloc参数template<typename T,          template<typename ELEM, typename ALLOC = std::allocator<ELEM>>          class CONT = std::deque> //兼容STL容器的模板实参,默认为deque,注意template和class两个关键词class ContainerWrapper {public:    CONT<T> elems;};ContainerWrapper<int> cw_default; //使用deque存储ContainerWrapper<double, std::vector> cw_customized; //指定底层存储类型为vector

非类型参数

C++模板还支持非类型参数,我们可以在模板定义中使用一个具体类型来指定它们。一个非类型参数可以是一个整形,或者是指针或左值引用。

template<unsigned N, unsigned M> //使用unsigned标记非类型参数int compare(const char (&left) [N], const char (&right) [M]) {    return compare(left, right);}compare("hi", "hello"); //推断出N=3,M=6template<typename T, int N>class WrapperWithNum {public:    T t;};WrapperWithNum<int, 1> wwn1;WrapperWithNum<int, 2> wwn2; //注意:虽然两个模板实例的T都是int,但是因为N不同,所以这是两个类型

注意:对于含有非类型参数的函数模板,整形推断的结果必须是一个常量表达式,指针和引用推断的结果必须指向具有静态生存周期的对象(static或者全局)或者是nullptr或0。

0 0
原创粉丝点击