找回密码
 会员注册
查看: 29|回复: 0

C++学习笔记

[复制链接]

2万

主题

0

回帖

6万

积分

超级版主

积分
64454
发表于 2024-9-20 15:46:05 | 显示全部楼层 |阅读模式
作者:readywang(王玉龙)template是c++相当重要的组成部分,堪称c++语言的一大利器。在大大小小的c++程序中,模板无处不在。c++templates作为模板学习的经典书籍,历来被无数c++学习者所推崇。第二版书籍覆盖了c++1114和17标准,值得程序猿们精读学习,特此整理学习笔记,将每一部分自认为较为重要的部分逐条陈列,并对少数错误代码进行修改一、函数模板1.1函数模板初探1.模板实例化时,模板实参必须支持模板中类型对应的所有运算符操作。template T max(const T &a, const T &b) {    return a > b? a : b;}class NdGreater {};int main() {    NdGreater n1, n2;    ::max(n1, n2); // 不支持 > 编译报错}2.模板编译时会进行两阶段检查a.模板定义时,进行和类型参数无关的检查,如未定义的符号等。b.模板实例化时,进行类型参数相关的检查。templatevoid foo(T t) {    undeclared(); // 如果 undeclared()未定义,第一阶段就会报错,因为与模板参数无关    static_assert(sizeof(T) > 10, "T too small"); //与模板参数有关,只会在第二阶段报错}3.根据两阶段检查,模板在实例化时要看到完整定义,最简单的方法是将实现放在头文件中。1.2模板参数推断1.函数模板的模板参数可以通过传递的函数参数进行推断。2.函数推断时会用到参数类型转换,规则如下:a.如果函数参数是按引用传递的,任何类型转换都不被允许。(此处有疑问,const转换还是可以的)b.如果函数参数是按值传递的,可以进行退化(decay)转换:const(指针或者引用只有顶层const可以被忽略)和volatile被忽略;引用变为非引用;数组和函数变为对应指针类型。template void RefFunc(const T &a, const T &b){};template void NoRefFunc(T a, T b){};int main() {    int *const ic = nullptr;    const int *ci = nullptr;    int *p = nullptr;    RefFunc(p, ic);  // ok 顶层const可以被忽略 T 为 int *    RefFunc(p, ci);  // error 底层const不可以忽略    NoRefFunc(p, ci); // error 底层const不可以忽略    int i = 0;    int &ri = i;    NoRefFunc(i, ri); // ok ri从int &转换为int    int arr[4];    NoRefFunc(p, arr);  // ok arr 被推断为int *    NoRefFunc(4, 5.0);  // error T 可以推断为int或double}3.上文的最后一句调用,类型推断具有二义性,无法正确实例化。可以通过以下方式解决a.类型转换:b.显式指定模板实参:    NoRefFunc(static_cast(4), 5.0);  // ok 类型转换    NoRefFunc(4, 5.0);  // 显式指定4.函数模板无法通过默认参数推断模板参数。如果函数模板只有一个函数参数,且函数参数提供了默认值的情况,应该为模板类型参数T也提供和函数参数默认值匹配的默认类型。template void Default(T t = 0){};Default(); // error 无法推断为inttemplate void Default(T t = 0){};Default(); // ok 默认类型为int1.3多模板参数1.当函数返回类型不能或不便由函数参数类型直接推断时,可以在函数模版中新增模板参赛指定返回类型。2.c++11之后,可以通过auto+decltype+尾后返回类型推断函数模板返回类型。当函数参数为引用类型时,返回类型应该为非引用。而decltype会保留引用,因此还需通过decay进行类型退化。3.c++14之后,可以通过auto直接推断函数模板返回类型,前提是函数内部的多个返回语句推断出的返回类型要一致。auto会自动对类型进行decay。4.c++11之后,可以通过common_type返回多个模版类型参赛的公共类型,common_type返回的类型也是decay的。#include// 单独通过RT指定返回类型template RT max1(const T1& a, const T2& b) { return a > b ? a : b; }// auto c++11支持 通过decay 进行类型退化 typename 用于声明嵌套从属名称 type 为类型而不是成员template auto max2(const T1& a, const T2& b) -> typename std::decay b ? a : b)>::type { return a > b ? a : b; }// auto c++14支持template auto max3(const T1& a, const T2& b) { return a > b ? a : b; }// common_type c++11支持 max4(5, 7.3) max4(7.4, 5) 的返回类型均被推断为doubletemplate typename std::common_type::type max4(const T1& a, const T2& b) { return a > b ? a : b; }1.4默认模板参数1.可以给模板参数指定默认值。// 默认模板参赛 因为RT需要T1 T2推断,所以放在最后template ::type>RT max5(const T1& a, const T2& b) { return a > b ? a : b; }1.5函数模板重载1.一个非模板函数可以和同名的函数模板共存,并且函数模板可实例化为和非模板函数具有相同类型参数的函数。函数调用时,若匹配度相同,将优先调用非模板函数。但若显式指定模板列表,则优先调用函数模板。2.函数模板不可以进行类型自动转换,非模板函数可以。#pragma oncetemplate T max(T a, T b) {    return a > b ? a : b;}template RT max(T1 a, T2 b) {    return a > b ? a : b;}int max(int a, int b) {    return a > b ? a : b;}int main() {    ::max(6, 8);  // 调用非模板函数    ::max(6, 8); // 调用函数模板 max    ::max('a', 'b'); // 调用函数模板 max    ::max(4, 4.0); // 通过类型转换调用非模板函数    ::max(4, 4.0); //指定了返回类型 调用max}3.调用函数模板时,必须保证函数模板已经定义。int max(int a, int b) {    return a > b ? a : b;}template T max(T a, T b, T c) {    return max(max(a,b),c);  //T为int时,并不会调用max 而是调用非模板函数}template T max(T a, T b) {    return a > b ? a : b;}max(1, 2, 3);  // 最终调用非模板函数比较max("sjx", "wyl", "shh"); // error 找不到二元的max二、类模板2.1stack类模板实现1.类模板不可以定义在函数作用域或者块作用域内部,通常定义在global/namespace/类作用域。#include#includetemplate class Stack{public:    void push(const T& value);    void pop();    T top();    int size() const { elem_.size(); };    bool empty() const { return elem_.empty(); };    void print(std:stream & out) const;protected:    std::vector elem_;};template void Stack::push(const T &value){    elem_.push_back(value);}template void Stack::pop(){    elem_.pop_back();}template T Stack::top(){    return elem_.back();}template void Stack::print(std:stream &out) const{    for (auto e : elem_)    {        out << e << std::endl;    }}2.2 stack 类模板使用1.直到 c++17,使用类模板都需要显式指定模板参数。2.类模板的成员函数只有在调用的时候才会实例化。2.3 部分使用类模板1.类模板实例化时,模板实参只需要支持被实例化部分所有用到的操作。int main(){    // 只会实例化类模板中的push 和 print函数    Stack s;    s.push(3);    s.print(std::cout);    // Stack未重载<<运算符,实例化print函数时失败    Stack
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-27 01:10 , Processed in 0.415937 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表