文档章节

Effective C++: auto类型推断.

SHIHUAMarryMe
 SHIHUAMarryMe
发布于 2016/03/30 20:25
字数 1508
阅读 136
收藏 0

1,请牢牢记住一点auto的推断其实是跟template的推断基本一致也有稍微的不同体现在std::initializer_list:

2,不能推断出一个模板中的另一个模板的类型(template<template<typenaem T> class A>);
 3, 当auto作为函数的参数类型或者返回类型的时候auto类型的推断规则无效!按照模板类型的推断规则来.

case 1: auto

 #include <iostream>
int main()
{
 int x = 27;
 int& xx = x;
 const int cx = x;
 const int& rx = x;
 
 auto n_ = 10; //auto = int;
 auto x_ = x; //auto = int;
 auto xx_ = x;//auto = int;
 xx_ = 100;
 std::cout<<x<<std::endl;
 auto cx_ = cx; //auto = int;
 auto rx_ = rx; //auto = int;
 
 cx_ = 10; //ok, but x is also 27.
 rx_ = 100;//as same sa above.
 
 
 return 0;
}

case 2:auto&

#include <iostream>
class Node{
 public:
  Node()=default;
  ~Node(){ std::cout<<"destroy"<<std::endl; }
};
int main()
{
 int x = 27;
 int& xx = x;
 const int cx = x;
 const int& rx = x;
 
 
 auto& x_ = x; //auto = int;
 x_ = 1;       //x = 1, now.
 std::cout<< x <<std::endl;
 
 auto& xx_ = x; //auto = int;
 xx_ = 2;
 std::cout<< xx_ <<std::endl;
 
 auto& cx_ = cx; //auto = const int;
 //cx_ = 3; //error.
 
 auto& rx_ = rx; //auto = const int;
 
 int* ptr = new int(2);
 //auto& p = &x; //error.
 auto& p =ptr; //p的类型是: int*(&); auto = int*; p是一个对ptr的引用. 
 *p = 10;
 std::cout<<p<<"  "<<ptr<<std::endl; //地址一样. 
 std::cout<<*p<<"  "<<*ptr<<std::endl;//数据一致. 
 delete ptr;
 
 int* ptr_two = new int(3);
 int* ptr_three = new int(4);
 std::cout<<ptr_two<<"  "<<ptr_three<<std::endl;
 
 auto& p_two = ptr_two;
 p_two = ptr_three; //现在ptr_two和p_two都指向了ptr_three. new int(3)还留在堆内!!内存泄漏了. 
 std::cout<<ptr_two<<"  "<<p_two<<std::endl;
 std::cout<<*ptr_two<<"  "<<*p_two<<std::endl;
 
 
 Node* ptr_node = new Node;
 auto& p_node = ptr_node;
 
 delete ptr_node;
 
 return 0;
}

case3: const auto

#include <iostream>
int main()
{
 int x = 27;
 const int cx = x;
 const int& rx = x;
 
 const auto y = 27; 
 const auto x_ = 2; //auto = int;
 const auto xx_ = x; //auto = int;
 const auto cx_ = cx; //auto = int;
 const auto rx_ = rx; //auto = int;
 
 int* ptr = new int(10);
 int* ptr_two = new int(20);
 const auto p = ptr;        //auto = int* , p的类型为int* const. 
 std::cout<<p<<"  "<<ptr<<std::endl;
 std::cout<<*p<<"  "<<*ptr<<std::endl;
 
 *p = 30;
 std::cout<<*p<<"  "<<*ptr<<std::endl;
 
 p = ptr_two; //error, p是一个顶层const. 
 
 delete ptr;
 delete ptr_two; 
 
 return 0;
}

case4: auto&&

 #include <iostream>
int main()
{
 int x = 27;
 const int cx = x;
 const int& rx = x;
 
 auto&& xx = 27; //auto = int;
 auto&& x_ = x; //auto = int&; 引用折叠 && + & = &; 
 x_ = 1;
 std::cout<< x <<std::endl;
 
 auto&& cx_ = cx; //auto = const int&; 引用折叠 && + & = &; 
 
 auto&& rx_ = rx; //auto = const int&; 同上. 
 
 return 0;
}

case 5: const auto&

#include <iostream>
int main()
{
 int x =27;
 const int cx = x;
 const int& rx = x;
 
 const auto& xx = 1; //auto = int;
 const auto& x_ = x; //auto = int;
 const auto& cx_ = cx; //auto = int;
 const auto& rx_ = rx; //auto = int;
 
 int* ptr = new int(10);
 int* ptr_two = new int(20);
 const auto& p = ptr; //ptr的类型是:int* const(&),auto = int*; p是一个对int* const类型的指针的引用!!!是引用!!!指针也能被引用!!.
 std::cout<<ptr<<"  "<<p<<std::endl;
 std::cout<<*ptr<<"  "<<*p<<std::endl;
 
 *p = 30;
 std::cout<<*ptr<<"  "<<*p<<std::endl;
 
 //p = ptr_two; //error, 这是一个顶层const 
 
 delete ptr;
 delete ptr_two;
 return 0;
}

case 6:数组和auto

#include <iostream>
int number_array[]{1, 2, 3};
int* arr = new int[3]{4, 5, 6};
const int* const ptr = nullptr;
int main()
{
 auto first = number_array; //auto = int* ;
 auto first_ = arr; //auto = int*;
 std::cout<<std::boolalpha<<std::is_same<int*, decltype(first)>::value<<" ";//输出: true.
 std::cout<<std::is_same<int*, decltype(first_)>::value<<std::endl;        //true.
  
 auto& second = number_array; //auto = int[3]; second的类型是 int (&)[3]. 
 auto& second_ = arr;          //auto = int*; second_的类型是int*(&); 
 std::cout<<std::boolalpha<<std::is_same<int(&)[3], decltype(second)>::value<<" ";//true
 std::cout<<std::is_same<int* (&), decltype(second_)>::value<<std::endl;         //true
 
 auto&& third = number_array; //auto = int(&)[3]; third的类型是 int(&)[3]. 
 auto&& third_ = arr;         //auto = int*(&);   third_的类型是 int*(&);
 std::cout<<std::boolalpha<<std::is_same<int(&)[3], decltype(third)>::value<<" ";//true
 std::cout<<std::is_same<int* (&), decltype(third_)>::value<<std::endl;         //true
 
 const auto forth = number_array; //auto = int*; forth的类型为: int* const,一个顶层const的指针. 
 const auto forth_ = arr;         //auto = int*; forth_的类型为: int* const,顶层const. 
 std::cout<<std::boolalpha<<std::is_same<int* const, decltype(forth)>::value<<" "; //true 
 std::cout<<std::is_same<int* const, decltype(forth_)>::value<<std::endl;         //true
 
 const auto& fifth = number_array; //auto = int[3]; fifth的类型为 const int(&)[3];
 const auto& fifth_ = arr;         //auto = int*; fifth的类型为 int* (&) const; 
 std::cout<<std::boolalpha<<std::is_same<const int(&)[3], decltype(fifth)>::value<<" ";//true
 std::cout<<std::is_same<int* const(&), decltype(fifth_)>::value<<std::endl;          //true
 
 
 
 return 0;
}

case 7: 函数和auto

 #include <iostream>
void function(const int& a, const int& b)
{
 std::cout<<a<<"  "<<b<<std::endl;
}
int main()
{
 auto func = function; //void (*)(const int&, const int&);
 (*func)(2, 0); 
 
 auto& func1 = function; //void (const int&, const int&);
 func1(3, 4);
 
 return 0;
}

看了这么多是不是发现其实跟模板类型推断一样呢?那么让我们来深入吧:

//c++提供了我们多种赋值的方式.
int a = 1;
int a(1);
int a{3};
int a={2};

但是我们用auto的话呢?

auto a = 1; //auto = int;
auto b(1); //auto = int;
auto c{3}; //auto = std::initializer_list<int>;
auto d={4}; //auto = std::initializer_list<int>;

还有:

auto list{1, 2, 3.0}; 
//error,竟然错了因为auto的类型被推断为std::initializer_list<int>但是3.0是一个float.

template<typename T>
void function(T param)
{ ...}

f({1, 2, 3}); //error!!!!!!!!
//由此我们可以看出不能推断出一个模板中的另一个模板的类型.

auto createInitList() //error, 这里竟然是和模板类型的推断规则一致的.
{
  return {1, 2, 3};
 }
 
 
 
 std::vector<int> v;
 auto resetV= [&v](const auto& newV){ v = newV; }
 
 resetV({1, 2, 4}); //error,这里相当于是reset(const T& newV),用的也是模板类型的推断规则.

关于尾至返回类型:

 #include <iostream>
#include <vector>
template<typename Container, typename Index>
auto function(Container& container, const Index& index)->decltype(container[index])
//如果使用了尾置返回类型auto是不会做任何事情的,其类型推断还是主要来自于decltype.
//由于std::vector的T& operator[](index),返回的是一个引用所以decltype推断出的类型也是一个引用. 
{
 return container[index];
}
int main()
{
 std::vector<int> v{1};
 function(v, 0)=2;
 
 std::cout<<v[0]<<std::endl; //输出为2. 
 
 return 0;
}

 错误的使用:

auto x; //error,不能知道x的类型.

int x1 = 10;
auto& ptr = &x1; //error.

 

语法(C++14):

decltype(auto) variable initializer  	(since C++14)
decltype(auto) function                 (since c++14)

针对: decltype(auto) function我们可以:

decltype(auto) function(int x, int y)

{

  return (x+y); //其实相当于调用 auto function(int x, int y)->decltype(x+y)

}

 

If the declared type of the variable is decltype(auto), the keyword auto is replaced with the expression (or expression list) of its initializer, and the actual type is deduced using the rules for decltype.

针对: decltype(auto) variable initializer我们可以:

decltype(auto) i =10; //i的类型为 int;

int x=10;

decltype(auto) y=(x); //相当于decltype((x)) y = x; 因此y的类型为 int&.

decltype(auto) list={1, 2}; //error, 因为{1, 2}不是表达式.

auto list_={1, 2}; //ok!

参考: https://my.oschina.net/u/2516597/blog/538605

 

© 著作权归作者所有

SHIHUAMarryMe
粉丝 13
博文 162
码字总数 138435
作品 0
武汉
程序员
私信 提问
C++11 FAQ中文版:decltype – 推断表达式的数据类型

C++11 FAQ中文版:decltype – 推断表达式的数据类型 二 24 Year 2011 陈 良乔 C++11 FAQ decltype – 表达式的数据类型 decltype(E)是一个标识符或者表达式的推断数据类型(“declared type...

长平狐
2013/01/11
137
0
C++11 FAQ中文版:auto – 从初始化中推断数据类型

Year 2011 陈 良乔 C++11 FAQ auto –从初始化中推断数据类型 考虑下面的代码: auto x = 7; 这里的变量x被7初始化,所以x的实际数据类型是int。通常,我们可以这样写: 这样,这个表达式计算...

长平狐
2013/01/11
64
0
C++11 FAQ中文版:返回值类型后置语法

二 28 Year 2011 陈 良乔 C++11 FAQ 返回类型后置语法 考虑下面这段代码: 函数mul()的返回类型要怎么写呢?当然,是“x*y类型”,但是这并不是一个数据类型,我们如何才能一开始就得到它的真...

长平狐
2013/01/11
188
0
C++11 中值得关注的几大变化(详解)

源文章来自前C++标准委员会的 Danny Kalev 的 The Biggest Changes in C++11 (and Why You Should Care),赖勇浩做了一个中文翻译在这里。所以,我就不翻译了,我在这里仅对文中提到的这些变...

红薯
2011/08/19
3.3K
14
C++ Primer 学习笔记(第三章:字符串、向量和数组)

C++ Primer 学习笔记(第三章:字符串、向量和数组) [TOC] 3.1 命名空间的声明 声明语句可以一行放多条。 位于头文件的代码,一般来说不应该使用声明。因为其内容会拷贝到每个使用该头文件的...

ShawnLue
2015/08/20
149
0

没有更多内容

加载失败,请刷新页面

加载更多

哪些情况下适合使用云服务器?

我们一直在说云服务器价格适中,具备弹性扩展机制,适合部署中小规模的网站或应用。那么云服务器到底适用于哪些情况呢?如果您需要经常原始计算能力,那么使用独立服务器就能满足需求,因为他...

云漫网络Ruan
今天
5
0
Java 中的 String 有没有长度限制

转载: https://juejin.im/post/5d53653f5188257315539f9a String是Java中很重要的一个数据类型,除了基本数据类型以外,String是被使用的最广泛的了,但是,关于String,其实还是有很多东西...

低至一折起
今天
15
0
OpenStack 简介和几种安装方式总结

OpenStack :是一个由NASA和Rackspace合作研发并发起的,以Apache许可证授权的自由软件和开放源代码项目。项目目标是提供实施简单、可大规模扩展、丰富、标准统一的云计算管理平台。OpenSta...

小海bug
昨天
11
0
DDD(五)

1、引言 之前学习了解了DDD中实体这一概念,那么接下来需要了解的就是值对象、唯一标识。值对象,值就是数字1、2、3,字符串“1”,“2”,“3”,值时对象的特征,对象是一个事物的具体描述...

MrYuZixian
昨天
8
0
解决Mac下VSCode打开zsh乱码

1.乱码问题 iTerm2终端使用Zsh,并且配置Zsh主题,该主题主题需要安装字体来支持箭头效果,在iTerm2中设置这个字体,但是VSCode里这个箭头还是显示乱码。 iTerm2展示如下: VSCode展示如下: 2...

HelloDeveloper
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部