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

类型别名与类型自动推导

类型别名与类型的自动推导

类型别名

为什么要引入类型别名?

为了给类型赋予特殊含义或便于使用

典型用途

(1)增强代码可移植性
例如:size_t (在不同系统中可能是unsigned int 或 unsigned long)
首先是无符号整型,可以表示任意尺寸的对象,通过别名来实现的
(2)简化复杂类型声明(如数组类型char[4])

实际意义

类型别名不是新类型,编译器会将其替换为原始类型处理。

引入类型别名的两种方式

传统方式 (typedef)

typedef 原类型 新类型名
typedef char MyCharArr[4]

缺点:对于复杂类型声明不直观,需要将新类型名插入原类型中间,本来是char[4],现在 char MyCharArr[4],char[4]中间插入了别名

现代方式(using

using 新类型名 = 原类型
using MyCharArr = char[4]    

优势:
声明形式更符合直觉(从左到右阅读)
特别适合模板别名
建议:C++11后优先使用using

类型别名与指针、引用的关系

应将指针类型别名视为一个整体,在此基础上引入常量表示指针为常量的类型

using IntPtr = int*;
int main(){int x = 3;const IntPtr ptr = &x; //const修饰整个IntPtr,即const修饰int*int y = 0;ptr = &y; //报错,ptr是常量指针,无法修改其指向
}

对于指针和引用来说,类型别名不是简单的替换

using IntPtr = int*;
//const修饰整个int*
const IntPtr ptr = &x; //指针的指向无法被修改
//上下不相同
//const修饰int
const int* ptr = &x;//所指向的值不能够被更改

不能通过类型别名构造引用的引用

using RefInt = int&; //引用的类型别名
using RefRefInt = RefInt&; //引用的引用,无效
#include<iostream>
#include<type_traits>
using RefInt = int&; 
using RefRefInt = RefInt&; 
int main(){
std::cout << is_same_v<int&, RefRefInt> << std::endl;
//结果为1,代表类型相同
}

类型自动推导

– 从 C++11 开始,可以通过初始化表达式自动推导对象类型
– 自动推导类型并不意味着弱化类型,对象还是强类型
强类型:任何变量的类型在生存周期(即从定义到销毁)其类型不会被改变

//浮点型+长整型得到什么类型?
什么类型? x = 3.5 + 15l;
//让编译器自己推导
auto x = 3.5 + 15l;
auto x; //错误
auto x{3}; //正确
auto x = 一个表达式; //正确

左值、右值

什么是左值、右值?
左值(lvalue,location value)是指在程序中有明确存储位置的对象,它们通常是具名变量,或者能被引用的对象。
1.左值可以出现在赋值语句的左侧,也可以出现在右侧。
2.有持久的存储位置:左值是具有稳定存储位置的对象,程序在其作用域内始终可以通过内存地址访问它。
可修改:通常左值是可修改的,但若被声明为 const,则不允许修改

int x = 10;   // x 是左值,因为它有明确的存储位置
x = 20;       // 可以修改 x 的值
int &ref = x; // 左值引用可以绑定到左值 x

右值(rvalue,read value)是指没有明确存储位置的临时对象,通常是字面量、表达式计算的结果,或需要被销毁的临时对象
1.右值一般只能出现在赋值语句的右侧,不能被赋值。
2.临时对象:右值通常是表达式计算的临时结果,无法通过地址来引用。
不可修改:右值通常不具备可修改性,特别是在表达式中,编译器会在表达式结束后销毁它。

int x = 10;
int y = x + 5;   // x + 5 是右值,表达式结果为临时值
int z = 20;      // 20 是右值常量

左值和右值的实际用途
(1)左值用于持久性对象:在程序中需要长期使用、反复访问的数据应该作为左值。例如,变量和对象都是左值。
(2)右值用于临时数据:如果一个数据只在短期内使用一次或立即处理完就可以销毁,适合使用右值。字面量、表达式结果通常就是右值。

自动推导的几种常见形式

● auto: 最常用的形式,但会产生类型退化

int x1 = 3;
int& ref = x1; //这里ref为左值
auto ref2 = ref; //这里的ref为右值,ref从int&退化为了int
int x[3] = {1,2,3};
auto x1 = x; //x退化为int*
int x[3] = {1,2,3};
auto& x1 = x; //x1类型为int(&)[3]

● const auto / constexpr auto: 推导出的是常量 / 常量表达式类型

const auto x = 3; //x类型为const int
constexpr auto x = 4; //x类型为const int,constexpr不是类型,只是修饰符表示在编译期间就确定为了常量
//-------------
const int x = 3;
const auto y = x; //这里不会产生类型退化,x仍为const int
//-------------
const int x = 3;
auto y = x; //这里x类型由const int 退化为 int

● auto& : 推导出引用类型,避免类型退化

const auto& x = 3; //x类型为const int&
//---------------
const int x = 3;
auto& y = x; //x没有发生类型退化,y的类型为const int&

decltype(这种类型自动推导不会产生退化)
● decltype(exp) :返回 exp 表达式的类型
如果是左值,则decltype会自动加引用(左值加引用)

int x = 3;
//decltype(x) x为左值但推导为int
int* ptr = &x; //ptr类型为int*
//*ptr为解引用,类型为int
//decltype(*ptr)为int自动加引用,int&

● decltype(val) :返回 val 的类型

int x = 3;
int& y1 = x; 
auto y2 = y1; //y1类型由int&退化为int
decltype(y1) y3 = y1; //y3的类型为int&

decltype(exp) 、decltype(val) 的例子

int x = 3;
int* ptr = &x;
//decltype(*ptr)为int&
//decltype(ptr)为int*
//decltype(x)为int
//decltype((x))为int&,(x)为左值且是表达式
const int y1 = 3;
const int& y2 = y1;
//decltype(y1)为const int
//decltype(y2)为const int&
//decltype((y1))为const int&
//decltype((y2))为const int&

● decltype(auto) :从 c++14 开始支持,简化 decltype 使用

decltype(3.5 + 15l) x = 3.5 + 15l; 
decltype(auto) x =3.5 + 15l;

● concept auto :从 C++20 开始支持,表示一系列类型( std::integral auto x = 3;)
限制类型推导的范围

#include<concept>
std::integral auto y = 3; //

C++20 引入的 ​​Concepts​​ 是模板编程的革命性特性,其核心作用是为模板参数提供​​编译时类型约束​​,显著提升代码的健壮性和可读性。

template<std::integral T>  // 约束 T 必须是整数类型
T square(T value) { return value * value; }

若传入 float,编译器会直接报错:“约束 std::integral 未满足”,而非冗长的模板实例化错误

http://www.xdnf.cn/news/12649.html

相关文章:

  • Redis数据持久化之RDB快照
  • 【走好求职第一步】求职OMG——见面课测验4
  • SAP学习笔记 - 开发27 - 前端Fiori开发 Routing and Navigation(路由和导航)
  • 算术图片验证码(四则运算)+selenium
  • 【大模型】大模型RAG(Retrieval-Augmented Generation)面试题合集
  • 欢乐熊大话蓝牙知识16:蓝牙是怎么找设备的?扫描与广播的“对话内幕”
  • Shell编程精髓:表达式与数组实战指南
  • DbServer链接KingBase8(人大)数据库
  • Android座舱系统Agent改造方案
  • day 47
  • 微前端架构下的B端页面设计:模块化与跨团队协作的终极方案
  • Python爬虫-爬取各省份各年份高考分数线数据,进行数据分析
  • 国产pcie switch,支持PCIE 3.0/4.0/5.0,支持昇腾310/910 GPU,支持龙芯、海光、飞腾
  • 小白成长之路-Linux Shell脚本练习
  • 2025年- H77-Lc185--45.跳跃游戏II(贪心)--Java版
  • Xilinx IP 解析之 Block Memory Generator v8.4 ——01-手册重点解读(仅 Native R
  • 前端开发面试题总结-JavaScript篇(二)
  • .Net Framework 4/C# 泛型的使用、迭代器和分部类
  • 本地windows服务器部署私有云网盘Nextcloud并无公网IP实现外部访问
  • 多线程中的泛型应用深度解析:类型安全与并发编程的完美融合
  • Java方法引用深度解析:从匿名内部类到函数式编程的演进
  • 算法训练第十天
  • 分享5个免费5个在线工具网站:Docsmall、UIED Tool在线工具箱、草料二维码、图片在线压缩、表情符号
  • 【嵌入式设备】使用PICO7抓取CH341A读写EEPROM的IIC波形
  • 视频字幕质量评估的大规模细粒度基准
  • 使用cd4060倒计时控制继电器,防止摩托车漏电
  • day 27 装饰器函数
  • SQL进阶之旅 Day 20:锁与并发控制技巧
  • C#:发送一封带有附件的邮件
  • Android实现点击Notification通知栏,跳转指定activity页面