c++11——auto,decltype类型推导
c++11中引入了auto和decltype关键字实现类型推导,通过这两个关键字不仅能够方便的获取复杂的类型,而且还能简化书写,提高编码效率。
auto和decltype的类型推导都是编译器在编译的时候完成的,auto是通过定义auto变量时候给出的表达式的值推导出实际类型,并且在声明auto变量时必须马上初始化;decltype通过表达式的值推导出实际的类型,但是可以只声明变量,而不赋值。
auto类型推导
1. auto推导
auto x = 5; //被编译器推导为int类型
auto pi = new auto(1); //编译器推导为int
const auto* v = &x, u = 5; //v为 const int*, u为 const int
static auto y = 0.1; //y为static const double
auto s; //出错! auto变量不能只声明不初始化
2. auto推导规则
(1)当不声明为指针或引用时,auto的推导结果和初始化表达式抛弃引用和cv限定符后的类型一致;(cv限定符: const volatile限定符)
(2)当声明为指针或引用时,auto的推导结果将保留初始化表达式的cv限定符。
int x = 0;
auto *a = &x; //a为 int*
auto b = &x; //b为 int*,auto可以自动识别指针类型
auto &c = x; //c为 int&
const auto e = x; //e为const int
auto f = e; //f为int (非指针或引用,则不保留cv限定符)
const auto& g = x; //g 为 const int&
auto& h = g; //h 为 const int&(指针或引用,保留cv限定符)
auto k = g;
3. auto的限制
(1)auto不能用于函数参数
(2)auto不能用于非静态成员变量
(3)auto无法定义数组
(4)auto无法推导出模板参数
void func(auto a = 1){}; //错误。auto不能用于函数参数
struct Foo{
auto var1 = 0; //错误,auto不能用于非晶态成员变量
static const auto var2 = 0;
} template<typename T>
struct Bar{}; int main(){
int arr[10] = {0};
auto aa = arr; //aa被推导为int*
auto rr[10] = arr; //错误,auto无法定义数组
Bar<int> bar;
Bar<auto> bb = bar; //错误,auto无法推导出模板参数
}
4. auto的使用场景
(1)变量类型名比较长比较复杂
//比如stl容器
std::map< double, double> result_map;
std::map< double, double>::iterator it = result_map.begin();
for(; it != result_map.end(); ++ it){};
//通过auto可以简化为
for (auto it = result_map.begin(); it != result_map.end(); ++it);
std::unordered_multimap< int, int> result_map;
std::pair< std::unordered_multimap< int, int>::iterator, std::unordered_multimap< int, int>::iterator> range = result_map.equal_range(key);
//通过auto简化为
auto range = result_map.equal_range(key);
(2)无法确定变量应该定义为什么类型
class Foo{
public:
static int get(void){
return 0;
}
};
class Bar{
public:
static const char* get(){
return "hello world";
}
}; template<typename A>
void func(void){
auto val = A::get();
cout << val << endl;
}
int main(){
func<Foo>();
func<Bar>();
}
decltype类型推导
1. decltype推导
decltype可以在编译时推导一个表达式的类型,语法格式如下:
decltype(exp). decltype只是推导表达式的类型,并不会对表达式求值。
int x = 0;
decltype(x) y = 3; //y被推导为int类型
decltype(x + y) z = 0; //z被推导为int
const int a = 1;
decltype(a) b = 2; //被推导为const int,尽管非指针或引用,仍然保持cv限定符
const int& i = 9;
decltype(i) h = x; //const int&
decltype(z)* p = &x; //p 为int*
decltype通过表达式得到的类型,可以保留住表达式的引用以及const限定符。对于一般的标记符表达式,decltype精确的推导出表达式定义本身的类型,不会像auto那样舍弃引用和cv限定符。
2. decltype推导规则
(1) exp是标识符,类访问表达式,decltype(exp)和exp的类型一致
(2) exp是函数调用,decltype(exp)和返回值的类型一致
(3) 其他情况,若exp是一个左值,则decltype(exp)是exp类型的左值引用,否则为和exp类型一致。
(1) exp是标识符,类访问表达式,decltype(exp)和exp的类型一致
(2) exp是函数调用,decltype(exp)和返回值的类型一致
(3) 其他情况,若exp是一个左值,则decltype(exp)是exp类型的左值引用,否则为和exp类型一致。 ```
(1)标识符、类访问表达式,则 decltype(exp)和exp的类型一致
class Foo{
public:
static const int Number = 0;
int x;
};
int n = 0;
volatile const int& x = n;
decltype(n) a = n; //int
decltype(x) b = n; //volatile const int&
decltype(Foo::Number) c = 0; //const int(没有static) Foo foo;
decltype(foo.x) d = 0; //int类型 (2) 函数调用,decltype(f(xx)) 和 函数返回值类型一致
const Foo f(){
...
}
decltype(f()) c; //const Foo (3) 带括号的表达式和加法运算表达式
struct Foo{
int x;
};
const Foo foo = Foo();
decltype(foo.x) a = 0; //a 被推导为int, 根据推导规则1
decltype((foo.x))b = a; //b 被推导为const int&,
//因为根据foo.x 为一个左值,可知括号表达式也是一个左值。则按照推导规则3,返回左值的引用,foo为const Foo,则foo.x为一个const int类型的左值,则decltype的推导结果 为 const int& int n = 1, m = 2;
decltype(n + m) c = 0; //c被推导为int, n + m 为右值,则推导规则3,
decltype(n += m) d = c; //d被推导为int &, n += m 为左值,则推导规则3,为exp的引用
//注意此时 n 仍然为1,而不是3,因为 decltype只是推导exp的类型,而不对exp进行求值
3. decltype的实际应用
(1)泛型编程中自动推导类型
decltype(ContainerT().begin()) it_; //获得某种类型容器的迭代器
(2)通过变量表达式抽取变量类型
vector<int> v;
....
decltype(v)::value_type i = 0; //知道v是一个vector,但是不知道里面的数据类型,则可以使用 decltype(v)::value_type
返回类型后置语法,auto和decltype结合使用
int& foo(int& i);
float foo(float& f);
//有如上两个函数,同名,但是返回值和参数类型不同。若想要用模板来实现两个同名函数的调用。
template<typename T>
decltype(foo(val)) func(T&val){
return val;
} //这样写编译不过,因为c++的返回值是前置语法,在返回值定义的时候参数变量还不存在,因此无法使用前置的decltype(foo(val)) 【需要获得decltype(foo(val))的时候,val还不存在】 但可以通过auto和decltype的自动类型推导完成。
template<typename T>
auto func(T& val) -> decltype(foo(val)) //返回值类型后置
{
return foo(val);
}
c++11——auto,decltype类型推导的更多相关文章
- 第4课 decltype类型推导
第4课 decltype类型推导 一.decltype类型推导 (一)语法: 1.语法:decltype(expr),其中的expr为变量(实体)或表达式 2.说明: ①decltype用于获取变量的 ...
- 第2课 auto类型推导(1)
第2课 auto类型推导(1) 一.auto类型推导 (一)与模板类型推导映射关系 1.auto类型推导与模板类型推导可以建立一一映射关系,它们之间存在双向的算法变换.auto扮演模板中T的角色,而变 ...
- Effective Modern C++翻译(3)-条款2:明白auto类型推导
条款2 明白auto类型推导 如果你已经读完了条款1中有关模板类型推导的内容,那么你几乎已经知道了所有关于auto类型推导的事情,因为除了一个古怪的例外,auto的类型推导规则和模板的类型推导规则是一 ...
- 类型推导:函数模板与auto
1.从函数模板谈起 函数模板的类型推导机制是在c++98时代就有的,auto的类型推导机制与其基本一致,所以先理解函数模板类型推导. 函数模板可以用如下代码框架表示: #template<typ ...
- Effective Modern C++:01类型推导
C++的官方钦定版本,都是以ISO标准被接受的年份命名,分别是C++98,C++03,C++11,C++14,C++17,C++20等.C++11及其后续版本统称为Modern C++. C++11之 ...
- 第1课 类型推导(1)_auto关键字
1. auto关键字 (1)auto的作用是让编译器自动推断变量的类型,而不需要显式指定类型.这种隐式类型的推导发生在编译期. (2)auto并不能代表实际的类型声明,只是一个类型声明的“占位符” ...
- C++11 类型推导decltype
我们之前使用的typeid运算符来查询一个变量的类型,这种类型查询在运行时进行.RTTI机制为每一个类型产生一个type_info类型的数据,而typeid查询返回的变量相应type_info数据,通 ...
- C++11 类型推导auto
在C++11之前,auto关键字用来指定存储期.在新标准中,它的功能变为类型推断.auto现在成了一个类型的占位符,通知编译器去根据初始化代码推断所声明变量的真实类型.使用auto会拖慢c++效率吗? ...
- C++11 - 类型推导auto关键字
在C++11中,auto关键字被作为类型自动类型推导关键字 (1)基本用法 C++98:类型 变量名 = 初值; int i = 10; C++11:auto 变量名 = 初值; auto i ...
随机推荐
- 从钉钉微应用定制化导航栏看如何实现Hybrid App开发框架
钉钉是阿里的一款企业应用APP,里面提供了混合微应用的SDK,这其实最好的一种APP架构模式.微信公众号浏览器JSSDK也提供了类似功能特性,在在交互性上没有钉钉深入. http://ddtalk.g ...
- java方法——重载2
什么是Java方法重载 方法重载的定义 1 对于同一个类,如果这个类里面有两个或者多个重名的方法,但是方法的参数个数.类型.顺序至少有一个不一样,这时候局构成方法重载. END 方法重载示例 1 pu ...
- linux支持的内存根文件系统
linux支持两种内存根文件系统:ramdisk和initramfs. ---------------------------------------------------------------- ...
- 【高可用HA】Nginx (1) —— Mac下配置Nginx Http负载均衡(Load Balancer)之101实例
[高可用HA]Nginx (1) -- Mac下配置Nginx Http负载均衡(Load Balancer)之101实例 nginx版本: nginx-1.9.8 参考来源: nginx.org [ ...
- ubuntu 命令 dpkg -l
dpkg -l 每条记录对应一个软件包,每条记录的第一, 二, 三个字符是软件包的状态标识, 后边依此是软件包名称,版本号, 和简单描述. 关于每个状态,可以参考 man dpkg-query 关于每 ...
- Ajax类
ajax.js -------------------------[ajax类]-------------------------- function Ajax(recvType){ var aj=n ...
- skynet1.0阅读笔记2_skynet的消息投递skynet.call
为了了解 skynet.call 的调用过程,需要先看看 skynet的队列是如何把包分到不同工作线程的.看下图 查看 global_queue 的skynet_globalmq_push和skyne ...
- 手工配置oracle数据库
手工配置Oracle 10G Enterprise Manager今天安装oracle,反复装了几遍都报下面错误:试了几种方法都不行:由于以下错误,Enterprise Manager配置失败启动Da ...
- r 数据分组处理
一.R语言实现数据的分组求和 实验数据集 姓名,年龄,班级 ,成绩, 科目 student <- data.frame ( name = c("s1", "s2&q ...
- 关于Cocos2d-x的瓦片地图
1.cocos2d-x的瓦片地图是用Tiled地图编辑器做的,这个软件开源,免费,一般都是用它制作瓦片地图. 2.瓦片地图是由块层和对象组成的,块层的作用是显示和一些重叠的时候覆盖角色的作用,而对象是 ...