C++11之auto类型推导

简介: C++11之auto类型推导

静态类型、动态类型与类型推导

在聊auto类型推导前,我们先理解一下静态类型动态类型吧。

我想对于C/C++程序员而言,静态类型应该都不陌生,因为C/C++语言所有的变量必须遵循先定义后使用

而python语言就是典型的动态类型,先用即用

例如下面代码:

a = 22
    print("a:", a)


对于编译器/解释器来讲,静态类型是在编译时期进行类型检查,动态类型则是在运行时期对类型检查。

运行时期对类型检查这种功能我们就称之为类型推导

auto的历史变更

在早期的C++中,auto的功能是具有自动存储期的局部变量,但是因为声明变量时默认都是自动存储期的局部变量,所以auto就显得很鸡肋,为此在C++11标准委员会就将auto重新定义了。由一个存储类型指示符(storage-class-specifier,如 static、extern等)变成了新的类型指示符(type-specifier,如int、float等)。


注意:auto声明的变量类型必须由编译器在编译时期推导得出,这会导致通过auto定义的变量必须赋予初值。见下图

auto类型推导的用法还是蛮简单的,这里我写了一个简单的例子。

#include <iostream>
int main()
{
  auto a = 111;
  auto b = 1.f;
  auto c = a + b;
  return 0;
}


auto的优势

auto这个关键字在实际开发中使用还是蛮频繁的(指C++11的auto)。所以对于一个经常使用STL的程序员简直就是福音,因为这能极大的改善声明变量类型的长度,使之简单化。


auto-自动类型推导

例如下面这个,对于一个map进行迭代器遍历,我们定义迭代器变量的类型就需要是std::map<int, std::string>::iterator ,这绝对是所有程序员不想看见的,太冗余了。

#include <iostream>
#include <map>
#include <iterator>
#include <string>
int main()
{
  std::map<int, std::string> mm;
  mm.insert(std::make_pair(1, "张三"));
  mm.insert(std::make_pair(2, "李四"));
  for (std::map<int, std::string>::iterator iter = mm.begin(); iter != mm.end(); ++iter)
  {
    std::cout << iter->first << "\t" << iter->second << std::endl;
  }
  return 0;
}

那么我们就可以用auto来优化。 这样的代码又简洁又易读。

#include <iostream>
#include <map>
#include <iterator>
#include <string>
int main()
{
  std::map<int, std::string> mm;
  mm.insert(std::make_pair(1, "张三"));
  mm.insert(std::make_pair(2, "李四"));
  for (auto iter = mm.begin(); iter != mm.end(); ++iter)
  {
    std::cout << iter->first << "\t" << iter->second << std::endl;
  }
  return 0;
}


auto还可以用在类型计算上,编译器会为你计算出最为适合的类型

#include <iostream>
int main()
{
  int a = 3;
  auto b = a * 1.1f;
  auto c = a * 1.1;
  return 0;
}


auto也不是万能的,在对于极端的精度计算时,auto也无能为力。

#include <iostream>
int main()
{
  unsigned int a = UINT_MAX;
  unsigned int b = 1;
  auto c = a + b;
  std::cout << c << std::endl;  // 0
  return 0;
}


虽然a+b会导致数值溢出问题,但是a+b的返回值是unsigned int所以auto并不能帮你自动扩展。

auto最大的优点在于”自适应“可应用于模板中

在下面这个例子中,Sum函数接受类型T1、T2的俩个变量,模板实例化时才可以确定类型。所以在Sum方法中的s变量的类型随着我们对模板的实例化不同它的类型也会不同。

#include <iostream>
template<typename T1, typename T2>
double Sum(T1 t1, T2 t2)
{
  auto s = t1 + t2;
  return s;
}
int main()
{
  auto a = Sum<int, double>(1, 1.2);
  auto b = Sum<int, int>(2, 6);
  return 0;
}

模板实例化为Sum<int, double>时,s的变量类型为double

模板实例化为Sum<int, int>时,s的变量类型为int

auto在其他场景的使用与限制


auto可引用于其他场合

  1. 可用于初始化列表
  2. 可用于new关键字在堆区创建变量
#include <iostream>
int main()
{
  auto b{ 1 }; // 可用于初始化列表
  auto c = new auto(1); // 可用于new关键字在堆区创建变量
  return 0;
}


auto不能使用的场合

  1. 不能用于函数参数
  2. 不能用于非静态成员变量
  3. 不能用于定义数组
  4. 不能当作模板参数
#include <vector>
void Fun(auto x = 1) // 1:auto函数参数 无法通过编译
{
}
class Test
{
public:
  auto var = 10;  // 2:auto非静态成员变量 无法通过编译
};
int main()
{
  auto arr[3] = { 1,2,3 }; // 3:auto数组 无法通过编译
  std::vector<auto> arr2; // 4:auto模板参数 无法通过编译
  return 0;
}


对于函数 fun来说,auto不能是其形参类型。你可能感觉对于fun来说,由于其有默认参数,所以应该推导fun形参x的类型为int型。但事实却无法符合大家的想象。因为auto是不能做形参的类型的。如果程序员需要泛型的参数,还是需要求助于模板。

对于结构体/类来说,非静态成员变量的类型不能是 auto的。同样的,由于var定义了初始值,你可能认为auto可以推导str成员var的类型为int 的。但编译器阻止 auto对结构体/类中的非静态成员进行推导,即使成员拥有初始值。

声明auto数组。我们可以看到,main中的声明auto arr[3]这样的数组同样会被编译器禁止。

在实例化模板的时候使用auto作为模板参数,如main中我们声明的 vector<auto> v。你可能认为这里一眼而知是int类型,但编译器却阻止了编译。

以上4种情况的特点基本相似,我们其实可以很容易能够推导出auto所在位置应有的类型,但现有的C++11的标准还没有支持这样的使用方式。

目录
相关文章
|
4天前
|
存储 安全 编译器
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
|
11天前
|
C++ 开发者
C++一分钟之-概念(concepts):C++20的类型约束
【7月更文挑战第4天】C++20引入了Concepts,提升模板编程的类型约束和可读性。概念定义了模板参数需遵循的规则。常见问题包括过度约束、约束不完整和重载决议复杂性。避免问题的关键在于适度约束、全面覆盖约束条件和理解重载决议。示例展示了如何用Concepts限制模板函数接受的类型。概念将增强模板的安全性和灵活性,但需谨慎使用以防止错误。随着C++的发展,Concepts将成为必备工具。
30 2
|
19天前
|
存储 安全 编译器
【C++航海王:追寻罗杰的编程之路】引用、内联、auto关键字、基于范围的for、指针空值nullptr
【C++航海王:追寻罗杰的编程之路】引用、内联、auto关键字、基于范围的for、指针空值nullptr
37 5
|
5天前
|
编译器 C++ 容器
在 C++ 中 auto什么意思
在 C++ 中 auto什么意思
|
9天前
|
C++ 开发者
C++一分钟之-概念(concepts):C++20的类型约束
【7月更文挑战第6天】C++20引入了Concepts,提升模板编程的精确性和可读性。概念允许设定模板参数的编译时约束。常见问题包括过度约束、不完整约束及重载决议复杂性。要避免这些问题,需适度约束、全面覆盖约束条件并理解重载决议。示例展示了如何定义和使用`Incrementable`概念约束函数模板。概念是C++模板编程的强大力量,但也需谨慎使用以优化效率和代码质量。
35 0
|
14天前
|
编译器 C++
【C++】详解初始化列表,隐式类型转化,类静态成员,友元
【C++】详解初始化列表,隐式类型转化,类静态成员,友元
|
15天前
|
算法 程序员 编译器
C++一分钟之概念(concepts):C++20的类型约束
【6月更文挑战第30天】C++20的Concepts革新了模板编程,允许更清晰地表达类型要求,提升代码可读性和编译错误反馈。本文探讨Concepts基础、应用场景、易错点及避免策略,展示如何通过概念定义如Iterable、Addable,创建更健壮的泛型代码,强调了理解和利用编译器错误信息的重要性,以及概念与类型别名的区别。Concepts现已成为现代C++程序员的关键技能。
17 0
|
17天前
|
程序员 编译器 C++
探索C++语言宝库:解锁基础知识与实用技能(类型变量+条件循环+函数模块+OOP+异常处理)
探索C++语言宝库:解锁基础知识与实用技能(类型变量+条件循环+函数模块+OOP+异常处理)
15 0
|
19天前
详细解读C++char类型函数
详细解读C++char类型函数
14 0
|
3天前
|
设计模式 安全 编译器
【C++11】特殊类设计
【C++11】特殊类设计
22 10