当前位置: 首页 > article >正文

C++理解模板类型推导

模板类型推导时auto类型推导的基础:应用于auto类型推导时,不像在模板类型推导中那么直观

函数模板我们一般这么使用(伪代码):

template<typename T>
void f(ParamType param);

一般这么调用:

f(expr);

在编译的时候,编译器通过expr来进行推导出T和ParamType

需要注意,T和ParamType是不同的,因为ParamType通常包含一定类型的装饰,例如const

template<typename T>
void f(const T& param);

int x =0;
f(x);

此时,T被推到成int,ParamType被推到成const int &

编译器在对T的类型进行推导时,不仅仅只取决于‘expr’的类型,还取决于‘ParamType’的形式。

主要有三种情况:

①‘ParamType’是指针或者引用,但不是通用引用

什么是通用引用?

在C++11及之后的标准版本里,“右值引用”(如T&&)和“左值引用”(如const T&T&),以及普通类型的规则变得更加复杂。当模板形参声明为T&&形式时,并不是简单地表示这个参数只能接收临时对象(即所谓的“右值”,例如函数返回的新创建的对象、字面常量等)。实际上,在某些条件下它可以绑定到任何表达式——无论是左右值都行;这种情形下的T&&被称为通用引用

如果expr的类型是一个引用,忽略引用的部分,然后利用expr的类型和ParamType对比去判断T的类型

template<typename T>
void f(T& param);//param是一个引用

int x = 27;
const int cx =x;
const int& rx = x;

f(x);//T是int,param此时推到类型为int&
f(cx);//T是const int,param此时推到类型为const int&
f(rx);//T是const int,param此时推到类型为const int&

上面展示的是左值引用参数的处理方式,右值引用也是如此

如果param是一个指针而不是引用,情况也是类似的

template<typename T>
void f(T*param);//param是一个指针
int x = 27;
const int *px = &x;

f(&x);//T是int,param的类型是int*
f(px);//T是const int,param的类型是const int *

②‘ParamType’是通用引用

通过引用参数的类型声明是T&&,如果expr是一个左值,T和ParamType都会被推到成左值引用(T&&->T&);如果expr是一个右值,那么同第一种情况

template<typename T>
void f(T&& param);//param现在是一个通用的引用

int x =27;
const int cx = x;
const int& rx =x;

f(x);//x是左值,所以T是int&,param的类型也是int&

f(cx);//cx是左值,所以T是const int&,param的类型也是const int&

f(rx);//rx是左值,所以T是const int&,param的类型也是const int&

f(27);//27是右值,所以T是int,param的类型也是int&&

③‘ParamType’既不是指针也不是引用

按pass-by-value处理:

如果expr的类型是个引用,将会忽略引用部分;如果expr是const的,也要忽略掉const.如果是volatile的,也要忽略掉

int x = 27;
const int cx =x ;
const int& rx =x ;

f(x);//T和param的类型都是int
f(cx);//T和param的类型都是int
f(rx);//T和param的类型都是int

如果指针(ptr)自己本身是被按值传递的,则忽略指针本身的const

template<typename T>
void f(T param);//param仍然是按值传递的(pass by value)
const char* const ptr ="WHAT CAN I SAY";//ptr是一个const指针,指向一个const对象
f(ptr);//给参数传递的是一个const char * const类型

param的推导出来的类型就是const char*

数组参数

虽然通常情况下,一个数组会退化成一个指向其第一个元素的指针,但是数组类型的指针类型是不一样的

const char name[]="ASDFGHJKL";//name类型是const char[]
const char* ptrToName = name;//数组被退化成指针

const char* 和const char[]是不一样的类型,但是基于数组到指针的退化原则,代码会被正常编译

但是如果将一个数组传递给一个按值传递的函数模板参数,会发生什么?

template<typename T>
void f(T param);
f(name);

显然不存在这种情况,不能将数组作为函数参数。

合法的写法如下

void myFunc(int param[]);
void myFunc(int* param);
f(name);//name是数组,但是T被推到成const char*

如上所示,数组声明被当作指针声明来处理

可以声明参数是数组的引用

template<typename T>
void f(T& param);  //引用参数的模板
f(name);				//传递数组给f

T被推到成了const char[],函数f的参数(数组的引用)被推到成const char (&)[]

通过声明数组的引用,可以创造出推导数组长度的模板:

//在编译的时候返回数组的长度(数组参数没有名字,因为只关心数组包含的元素的个数)
template<typename T, std::size_t N>
constexpr std::size_t arraySize(T (&)[N])noexcept
{
  return N;//constexpr和noexcept在随后的条款中介绍
}
int keyVals[]= {1,3,7,9,11,22,35};//keyVals有七个元素
int mappedVals[arraySize(keyVals)];//mappedVals长度也是七

数组替代方案:

std::array<int,arraySize(keyVals)> mappedVals;//mappedVals长度是七

函数参数

函数类型可以被退化为函数指针

void someFunc(int ,double);//someFunc是一个函数,类型是void(int,double)
template<typename T>
void f1(T param);//按值传递
template<typename T>
void f2(T& param);
f1(someFunc);//param被推导成函数指针,类型是void(*)(int,double)
f2(someFunc);//param被推导成函数引用,类型是void(&)(int,double)

要点:

①在模板类型推导期间,引用参数被视为非引用,忽略其引用性质

②在推到通用引用形参的类型时,左值实参会得到特殊处理

③在推导值传递的形参类型时,const和volatile参数被视为非const和非volatile的

④在模板类型推导期间,数组或者函数实参会退化为相应的指针,除非他们用于初始化引用


http://www.kler.cn/a/580977.html

相关文章:

  • 基于Golang的微服务——Consul
  • 【Prometheus】层层解析prometheus如何监控k8s核心组件
  • 如何利用PyPDF2库轻松提取PDF中的文本?
  • 【eNSP实战】交换机配置端口隔离
  • PDF文件中的颜色是什么原理?
  • 一招解决Pytorch GPU版本安装慢的问题
  • DeepSeek+Maxkb+Ollama+Docker搭建一个AI问答系统
  • 数字IC后端设计实现教程 |Innovus ICC2 Routing Pin Access Setting设置方法
  • coze ai assistant Task 1
  • Java集成消息队列实战:从RabbitMQ到Kafka的完整解决方案 [特殊字符]
  • 雷池WAF上游服务器访问状态异常的解答
  • 提升工地安全:视觉分析助力挖掘机作业监控
  • 【FreeRTOS】FreeRTOS操作系统在嵌入式单片机上裸机移植
  • HarmonyOS:应用文件概述(通俗易懂解释版)
  • 《Spring日志整合与注入技术:从入门到精通》
  • 学习文章:Spring Boot 中如何使用 `@Async` 实现异步处理
  • CTF杂项——[陇剑杯 2023]WS(一~四)
  • 软考高级信息系统项目管理师笔记-第20章高级项目管理
  • Web3 中的智能合约:自动化与去信任化的力量
  • 中信银行太原分行营业部开展“金融知识普及共筑消费安全”宣传活动