模板与泛型编程

本文详细介绍了C++中的模板编程,包括函数模板、类模板、模板参数、成员模板、模板实参推断、重载与模板、可变模板参数以及模板特例化。内容涵盖模板的定义、使用方法、效率与灵活性,以及如何控制实例化和实参推断。特别强调了模板实参推断中的类型转换、函数指针、尾置返回类型和std::move的使用。此外,还讨论了可变参数模板的编写和转发参数包的应用。
摘要由CSDN通过智能技术生成

1.定义模板

​ 模版是C++泛型编程的基础,一个模版就是一个类或函数的蓝图或者说是公式:例如在使用vector这样的泛型类型,或者是find函数这样的泛型类型,我们可以将蓝图转换为特定的类或者是函数,这种转换发生在编译时。当我们调用一个模板时,编译器会使用实参的类型来确定绑定到模版参数T上的类型,之后编译器利用推断出的模版参数来实例化一个特定版本的函数,这个过程被称之为实例化。编译器遇到一个模版的定义时,并不会产生代码,只有当我们实例化出模版的一个特定版本的时候,编译器才会产生代码,因此有很多bug等问题要等用到(实例化)的时候才会发现

1.1 函数模板

  1. 类型参数之前必须加上 typename 或者 class 这两个关键字,这两个关键字含义相同,可以互换使用。但有些地方只有 typename 才可以用,比如当我们表示一个容器类型时,只能使用 typename 关键字。

  2. 模板类型参数包括类型参数非类型模板参数。类型参数很好理解,不多赘述。下面讲解非类型模板参数。一个非类型参数表示一个值而非一个类型。我们通过一个特定的类型名而非关键字 class 或者 typename 来指定非类型参数。

    当一个模板被实例化时,非类型参数被一个用户提供的或编译器推断出的值所代替。这些值必须是常量表达式,从而允许编译器在编译时实例化模板。

    示例如下:

    template <unsigned N, unsigned M>	//N和M分别表示数组的长度
    int compare(const char (&p1)[N], const char (&p2)[M])
    {
        return strcmp(p1, p2);
    }
    

    当我们调用这个版本的compare时:compare(“hi”, “mom”); 编译器使用字面常量的大小来代替N和M,从而实例化模板。

    一个非类型参数可以是一个整型,或者是一个指向对象或函数类型的指针或(左值)引用。绑定到非类型整型参数的实参必须是一个常量表达式。绑定到指针或引用非类型参数的实参必须具有静态的生存期(参见第12章,第400页)。我们不能用一个普通(非static)局部变量或动态对象作为指针或引用非类型模板参数的实参。指针参数也可以用nullptr或一个值为0的常量表达式来实例化。

  3. inlineconstexpr 这两个说明符的位置和普通的非模板函数一样。

  4. 与非模板代码不同,函数模板和类模板成员函数的定义通常放在头文件中,即模板的头文件中通常既包括声明也包括定义。

1.2 类模板

  1. 为了使用类模板,我们必须在模板名后的尖括号中提供额外信息——显示模板实参,它们用来代替模板参数的模板实参列表。

  2. 默认情况下,对于一个实例化了的类模板,其成员只有在使用时才被实例化。这一特性使得即使某种类型不能完全符合模板操作的要求,我们仍能使用该类型实例化类。

  3. 我们可以在类模版的内部或者外部对类模版的成员函数进行定义,定义在类模版内的成员函数被隐式的声明为inline函数。

  4. 在类模版自己的作用域中(即类内),我们可以直接使用模版名而不提供实参(不需要这个东西了),而在类外则需要指定模版参数。

  5. 当一个类模版包含一个非模版友元,则友元被授权可以访问所有的模版实例,如果友元自身是模版,类可以授权给所有友元模版实例,也可以只授予给定实例。如果想要所有实例成为友元,友元声明中必须使用与类模版不同的模版参数。注意这里的前置声明问题。(参见589页)

  6. C++11新标准:可以将模版参数类型声明为友元,比如将 Sales_data 类将称为 Bar<Sales_data> 的友元。

    虽然友元通常来说应该是一个类或是一个函数,但我们完全可以用一个内置类型来实例化Bar。这种与内置类型的友好关系是允许的,以便我们能用内置类型来实例化Bar这样的类。

  7. C++11新标准:我们可以定义一个typedef来引用实例化的类,还可以使用using来声明类型别名。

    typedef Blob<string> StrBlob;	//引用了实例化的类
    template <typename T> using twin = pair<T, T> //起了一个别名
    template <typename T> using patrNo = pair<T, unsigned>;
    partNo<string> books;	//books是一个pair<string, unsigned>
    partNo<Student> kids;	//kids是一个pair<Student, unsigned>
    

1.3 模板参数

  1. 在类模板中,默认情况下,C++语言假定通过作用域运算符访问的名字不是类型。因此,如果希望使用一个模板类型参数的类型成员,就必须显示告诉编译器该名字是一个类型。我们通过使用关键字typename来实现这一点。例如如下代码:
template <typename T>
typename T::value_type top(const T& c)
{
    if(!c.empty())
        return c.back();
    else
        return typename T::value_type();
}

​ 例如该函数的返回值以及第七行,通过typename指定返回值为T类型的value_type。此处只能使用 typena

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值