C++进阶 —— auto/decltype(C++11新特性)

本文详细介绍了C++11中的两大重要新特性:auto类型推导和decltype类型推导。通过具体示例展示了如何利用这些特性简化代码编写,提高开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一,auto 类型推导

二,decltype 类型推导


        在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了C++98称为C++11之前的最新C++标准名称;不过由于TC1主要是对C++98标准中的漏洞进行修复,语言的核心部分则没有改动,因此人们习惯的把两个标准合称为C++98/03标准;从C++0x到C++11,C++标准十年磨一剑,第二个真正意义上的标准姗姗来迟; 相比于C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言;相比较而言,C++11能更好地用于系统开放和库开发,语法更加泛化和简单化,更加稳定和安全,不仅功能强大,而且能提升程序员的开发效率;

一,auto 类型推导

        早期C/C++中,使用auto修饰的变量具有自动生命周期变量(多余,变量默认拥有自动的生命周期),但一直没有人去使用;C++11中,auto不在是一个存储类型标识符(如 static、register、mutable 等),而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时推导而得;

// C++98/03,可以默认写成 int i = 0;
//默认自动具有生命周期;
auto int a = 0;  
//static会更改生命周期或链接属性
static int a = 0;

        由于定义变量时,必须先给出变量的实际类型,但有些情况可能不知道所需要实际类型,或类型书写起来特别复杂;在C++11中,可使用auto来根据变量初始化表达式类型推导变量的实际类型,可给程序的书写带来许多方便;

  • 使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型;
  • auto并非是一种类型的声明,而是一个类型声明时的占位符,编译器在编译时会将auto替换为实际变量类型;因为是编译时推导的,所以并不影响运行时的性能;
  • 为了避免与C++98中的auto混淆,C++11保留了auto作为存储类型标识符的用法;
  • auto实际中最常见的优势用法,是跟范围for循环及lambda表达式等进行配合使用;
//short取值范围-32768 ~ 32767
short a = 32670;
short b = 32670;
//如c类型为short,超过取值范围,数据会丢失
//short c = a + b;
//auto会自动根据a+b的结果推导出c的实际类型为int 
auto c = a + b;
//实际类型const int&
const auto& d = c;
map<string, string> mp{{"apple","苹果"},{"banana","香蕉"}};
//迭代器类型复杂
map<string, string>::iterator it = mp.begin();
//auto会自动推导出,书写非常方便,还不容易出错
auto it = mp.begin();

 auto使用细则

  • auto可与指针和引用结合起来使用,用auto声明指针类型时,用auto和auto*没有区别,但用auto声明引用类型时则必须加&;
  • 在同一行定义多个变量,但在同一行声明多个变量时,必须是相同类型,否则编译器报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量;
int a = 10;
int& ra = a;
auto b = a; //int
//推导指针
auto c = &a; //int*
auto* cc = &a; //int*
//推导引用
auto d = ra; //int
auto& dd = a; //int&
//定义多个变量,必须是相同类型
int a;string b;
//auto c = a, d = b;
  • 当不声明不带引用时,auto 的推导结果不带 cv 限定符(const 和 volatile 限定符的统称)后类型一致;
  • 当声明带上引用时,auto 的推导结果将保持初始化表达式的 cv 属性;
const int& a = 1;
auto b1 = a; //推导类型为int
auto& b2 = a; //推导类型为const int&

auto不能推导的场景

  • auto不能作为函数的参数;
  • auto不能直接用来声明数组;
  • auto无法推导模板参数;
  • 不可在类内声明非静态auto成员变量;
//auto不能作为函数的参数
void fun(auto a){}
//auto不能直接用来声明数组
auto arr[] = { 1,2,3 };
//auto无法推导模板参数
vector<auto> v = { 1,2,3 };
//不可在类内声明非静态auto成员变量;
class Foo {
public:
	auto bar = "Hello, world!";   
};

二,decltype 类型推导

        auto使用的前提是,必须对auto声明的类型进行初始化,否则编译无法推导出实际类型;但有时候可能需要根据表达式运行完成之后结果的类型进行推导(因为编译期间,代码不运行),此时无法使用auto;需要程序运行完才能知道结果的实际类型,即RTTI(Run-Time Type Identification 运行时类型识别);运行时类型识别的缺陷,是降低程序运行的效率;C++98中已经支持RTTI,typeid只能查看类型,不能用其结果定义类型,dynamic_cast只能应用于含有虚函数的继承体系中;

        decltype操作符(也是关键字),根据表达式(包括变量、函数调用、或者表达式等)在编译时进行类型推导,不会对操作数求值(类似sizeof);

//语法格式
decltype(expression) var;
  • 括号内为变量或左值,则返回该变量所指对象的类型(包括 cv 限定符和引用等修饰符);
    • 可使用 std::remove_cv 和 std::remove_reference 进行去除修饰符;
const int a = 1;
const int& b = a;
decltype(a) var1 = 2; //推导类型为const int
decltype(b) var2 = b; //推导类型为const& int
  • 括号内为函数时,则返回该函数返回值的类型;
const char fun();
decltype(fun()) b = 1; //推导类型为char
const decltype(fun()) b = 1; //推导类型为const char

const char* fun();
decltype(fun()) b; //推导类型为const char*

const char& fun();
decltype(fun()) b = 1; //推导类型为const char&
void* GetMemory(size_t size){return malloc(size);}

int main()
{
	//只是推演,不会执行函数
	cout << typeid(GetMemory).name() << endl;
	cout << typeid(GetMemory(0)).name() << endl;
}
  • 括号内为表达式时,则返回该表达式结果的实际类型;
//推导a+b的实际类型来定义c的类型
decltype(1 + 1.0) c;
cout << typeid(c).name() << endl;
  • 推导函数返回值类型(auto结合decltype构成返回类型后置语法);
//auto此时无类型推导含义,只是返回类型后置语法的组成部分
auto add(int a, int b)->decltype(a + b)
{
	return a + b;
}
  • 推导 lambda 表达式类型;
auto lambda_fun = [](int a, int b) -> decltype(a + b)
{
	return a + b;
};
  • 推导模板参数类型;
template<typename T1, typename T2>
auto add(T1 a, T2 b) -> decltype(a + b) {
	return a + b;
}
//C++14 中引入的类型推导关键字
//推导出返回值类型,并保留了原有变量的类型和修饰符
template<typename T>
decltype(auto) func(T&v1)  //可把auto理解成要推导的类型,推导过程我们采用decltype
{
   return v1;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值