news 2026/7/2 2:15:29

自动类型推导

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
自动类型推导

auto

auto可以像别的语言一样自动推导出变量的实际类型。

在实际中,auto像是一个”占位符“,使用auto声明的变量必须要进行初始化,以让编译器推导出它的实际类型,在编译时将auto换成真正的类型。

语法:

auto 变量名 = 变量值

实际使用例子:

#include <iostream> using namespace std; int main() { //没有const修饰 auto x = 3.14; //double auto y = 520; //int auto z = 'a'; //char //auto nb; //语法错误 //auto double nbl; //语法错误 int temp = 110; auto* a = &temp; //&temp:int* auto*:int* auto:int auto b = &temp; //auto:int* auto& c = temp; //auto:int auto d = temp; //auto:int //有const修饰 int tmp = 250; const auto a1 = tmp; //auto:int a1:const int auto a2 = a1; //a1不是指针也不是引用 auto:int a2:int const auto& a3 = tmp; //a3:const int& auto:int auto& a4 = a3; //a3是引用类型 a3:const int& a4:const int& auto&:const int& auto:const int auto* pt4 = &a1; //&a1是地址 a1:const int pt4:const int* auto:const int system("pause"); return 0; }

需要注意的是:

在auto和指针、引用结合在一起时,推导的结果会保留const、volatile关键字(volatile表示变量,经常修改的变量)

  • 当变量不是指针或者引用类型时,推导的结果中不会保留const、volatile关键字。
  • 当变量时指针或者引用类型时,推导的结果中会保留const、volatile关键字。

就如上述代码中的//有const修饰后面的代码,需要注意变量是否为指针或者引用类型。

auto不能推导的4个情况

1. 不能作为函数参数使用,因为只有在函数调用的时候才会给函数参数传递实参,auto要求必须要给修饰的变量赋值,因此二者不矛盾。
int func(auto a, auto b) { //error cout << "a: " << a << ", b: " << b << endl; }
2.不能用于类的非静态成员变量的初始化
class Test { auto v1 = 0; //error static auto v2 = 0; //error,类的静态非常量成员不允许在类内部直接初始化 static const auto v3 = 10; //ok };
3. 不能使用auto关键字定义数组
int func() { int array[] = { 1, 2, 3, 4, 5 }; //定义数组 auto t1 = array; //ok, t1被推导为 int* 类型 auto t2[] = array; //error, auto无法定义数组 auto t3[] = { 1, 2, 3, 4, 5 }; //error, auto无法定义数组 }
4. 无法使用auto推导出模板参数
template <typename T> struct Test {}; int func() { Test<double> t; Test<auto> t1 = t; //error,无法推导出模板类型 return 0; }

auto常用用途

1. 用于STL容器的遍历

在遍历时我们会写:map<int, string>::iterator it = mp.begin();这样的迭代器,在有了auto之后可以用auto代替map<int, string>::iterator

#include <iostream> #include <map> using namespace std; int main() { //key:int , value:string map<int, string>mp; mp.insert(make_pair(1, "ace")); mp.insert(make_pair(2, "sabo")); mp.insert(make_pair(3, "luffy")); //map<int, string>::iterator it = mp.begin(); auto it = mp.begin(); for (; it != mp.end(); it++) { cout << "key: " << it->first << ", value: " << it->second << endl; } system("pause"); return 0; }

如上述代码,在有了auto之后迭代器的定义简单方便了很多。

2. 用在泛型编程

在使用模板的时候,很多情况下我们不知道变量应该定义成什么类型,比如下面的代码:

#include <iostream> #include <map> using namespace std; class T1 { public: static int get() { return 10; } }; class T2 { public: static string get() { return "hello, world"; } }; //template<class T, typename P> template <class T> void func() { auto ret = T::get(); //P ret = T::get(); cout << "ret: " << ret << endl; } int main() { func<T1>(); func<T2>(); //func<T1, int>(); //func<T2, string>(); system("pause"); return 0; }

上述代码中T1::get()返回int类型,T2::get()返回string类型。在模板中调用时就能不确定返回什么类型的值,使用auto解决了这一问题,如果不用auto只能像注释中的那样多定义一个模板参数来确定返回的值时什么类型。

decltype

C++11增加了decltype关键字,它是在编译器编译的时候推导出一个表达式的类型;

decltype不需要定义变量,不需要初始化变量也可以推导类型。语法:decltype(表达式)

decltype是"declare type"的缩写,译为"声明类型"。decltype的推导是在编译时完成的,只是用于推导表达式的类型,并不会计算表达式的值,如下:

int a = 10; decltype(a) b = 99; //a:int b:int decltype(a+3.14) c = 3.14159; //a+3.14:double c:double decltype(a+b*c) d = 234.2343; //a+b*c:double d:double decltype(a) e; //a:int e:int

decltype只是使用了括号中表达式的类型,后面的变量定义和括号中表达式值的大小无关。

auto只能推导已初始化的变量类型,decltype推导的可以不进行初始化。

decltype的推导规则

decltype的3个场景的使用规则:

1. 表达式为普通变量或者普通表达式或者类表达式

表达式为普通变量或者普通表达式后者类表达式时,decltype推导出的类型和表达式的类型是一样的。

#include <iostream> using namespace std; class Test { public: int num = 9; string text; static const int value = 110; }; int main() { int x = 99; const int& y = x; decltype(x) a = x; //x:int a:int decltype(y) b = x; //y:const int& b:const int& decltype(Test::value) c = 0; //Test::value : const int c:const int Test t; decltype(t.text) d = "hello, world"; //t.text : string d:string system("pause"); return 0; }
2.表达式是函数调用

表达式是函数调用的时候,decltype推导出的类型和函数返回值是一致的。

#include <iostream> using namespace std; class Test { public: int num = 9; string text; static const int value = 110; }; //函数声明 int func_int() {}; int& func_int_r() {}; int&& func_int_rr() {}; const int func_cint() {}; const int& func_cint_r() {}; const int&& func_cint_rr() {}; const Test func_ctest() {}; int main() { int n = 100; decltype(func_int()) a = 0; //func_int():int a:int decltype(func_int_r()) b = n; //func_int_r():int& b:int& decltype(func_int_rr()) c = 0; //func_int_rr():int&& c:int&& decltype(func_cint()) d = 0; //func_cint():const int d:int (这里是因为func_cint()函数返回的值是一个纯右值,就会被推导为int;对于右值而言只有类类型可以携带const、volatile限定符,其他需要忽略这两个限定符) decltype(func_cint_r()) e = 0; //func_cint_r():const int& e:const int& decltype(func_cint_rr()) f = 0; //func_cint_rr():const int&& f:const int&& decltype(func_ctest()) g = Test(); //func_ctest:const Test g:const Test system("pause"); return 0; }

上述代码中func_cint()返回的是一个纯右值(再func_cint()运行之后不再存在数据,也就是返回的是临时性的数据),对于纯右值而言,只有类类型会携带const、volatile限定符,其他需要忽略这两个限定符。

上例中用到了int&&等右值引用,这里补充一下右值引用相关内容(以int&&为例):

int&是左值引用,绑定到可命名、可持久存在的对象;

C++11引入了int&&右值引用

int&&为右值引用,绑定到临时对象或将要被销毁的对象,用于移动语义和完美转发。

int a = 10; int& b = a; //正确 int& c = 30; //错误 int&& r = a; //错误 int&& d = 30; //正确 int&& e = 20+10; //正确

int&&的最重要的应用:移动语义

在移动右值的时候可以避免深拷贝,性能更高:

vector<int> a = {1,2,3}; vector<int> b = std::move(a);

其中std::move()是c++11引入的一个函数,它的作用是:把一个对象强制转换成右值引用,从而触发移动语义,注意:std::move()本身并不会移动任何数据,它只是一个类型转换。

#include <iostream>
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 2:13:31

Go 内存逃逸分析:编译器分配决策的底层逻辑与优化指南

Go 内存逃逸分析&#xff1a;编译器分配决策的底层逻辑与优化指南 一、栈上的数据为何"叛逃"到堆上&#xff1a;逃逸分析的工程意义 Go 的编译器内置逃逸分析&#xff08;Escape Analysis&#xff09;&#xff0c;它在编译期决定每一个变量应该分配在栈上还是堆上。这…

作者头像 李华
网站建设 2026/7/2 2:13:19

MiniMax与阶跃星辰2026大模型实测:国产新势力谁更懂开发者?

MiniMax与阶跃星辰2026大模型实测&#xff1a;国产新势力谁更懂开发者&#xff1f;说到2026年上半年的国产大模型生态&#xff0c;很多开发者可能还停留在去年的印象里。但说实话&#xff0c;这半年的迭代速度快得让人有点跟不上。MiniMax和阶跃星辰&#xff08;StepFun&#x…

作者头像 李华
网站建设 2026/7/2 2:12:08

新疆乌鲁木齐专业的体考学校升学率高的

在新疆乌鲁木齐&#xff0c;随着越来越多高中生选择通过体育升学&#xff0c;体考学校如雨后春笋般涌现。那么&#xff0c;究竟哪家体考学校的升学率高呢&#xff1f;今天&#xff0c;我们就来深入探讨一下&#xff0c;重点介绍一家扎根本地、实力出众的体考机构——新疆健安体…

作者头像 李华
网站建设 2026/7/2 2:09:29

YOLO目标检测论文快速产出:四大改进策略与全流程实践指南

这次我们来看一个对研究生和本科毕设同学非常实用的主题&#xff1a;如何在导师放养、时间紧迫的情况下&#xff0c;围绕YOLO目标检测&#xff0c;快速、高效地产出一篇合格的学术论文。这不仅仅是“水”一篇论文&#xff0c;而是掌握一套可复用的方法论&#xff0c;让你在有限…

作者头像 李华
网站建设 2026/7/2 2:07:15

如果在一个函数中的复合语句中定义了一个变量,则该变量( )。

只在该复合语句中有效 B 在本程序范围内有效 C 在该函数中有效 D 为非法变量 2.当函数的参数是普通变量时&#xff0c;关于函数的形参和形参&#xff0c;以下说法正确的是&#xff08; &#xff09;。\ A 实参和与其对应的形参共占用一个存储单元 B 只有当实参和与其对应的…

作者头像 李华