C++ 11 auto 与 decltype

Posted Overboom

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ 11 auto 与 decltype相关的知识,希望对你有一定的参考价值。

C++11 引入了auto和decltype关键字实现类型推导,通过这两个关键字不仅能方便地获取复杂类型,而且还能简化书写,提高编码效率。

1. auto

编程时候常常需要把表达式的值付给变量,需要在声明变量的时候清楚的知道变量是什么类型。然而做到这一点并非那么容易(特别是模板中),有时候根本做不到。为了解决这个问题,C++11新标准就引入了auto类型说明符,用它就能让编译器替我们去分析表达式所属的类型。和原来那些只对应某种特定的类型说明符(例如 int)不同。auto 让编译器通过初始值来进行类型推演。从而获得定义变量的类型,所以说 auto 定义的变量必须有初始值。

1.1 auto推导规则

auto可以同指针、引用结合起来使用,还可以带cv限定符(cv-qulifier, const和volatile限定符的统称)。

int x = 0;

auto *a = &x;				// a为int*, auto被推导为int
auto  b = &x;				// b为int*, auto被推导为int *
auto &c = x;				// c为int &, auto被推导为int
auto  d = c;				// d为int, auto被推导为int

const auto e = x;			// e为const int
auto f = e;					// f 为int

const auto &g = x;			// g为const int&
auto& h = g;				// f为const int &  

通过上面示例,可以得到两条规则:
1> 当不声明指针或引用时,auto的推导结果和初始化表达式抛弃引用cv限定符后类型一致
2> 当声明为指针或引用时,auto的推导结果将保持初始化表达式的cv属性。

1.2 auto的限制

void func(auto a = 1) 		// error: auto不能用于函数参数

struct Foo 

	auto var_ = 0;								//error:auto不能用于非静态成员变量
	static const auto var2_ = 0;	//OK: var2_ 为static const int
;

template <typename T>
struct Bar ;

int main(void)

	int arr[10] = 0;
	auto aa = arr;				// ok,aa为int
	auto rr[10] = arr;		// error,auto无法定义数组
	
	Bar<int> bar;
	Bar<auto> bb  = bar; 	// error:auto无法推导出模板参数

	return 0;

1> auto不能用作函数参数
2> auto不能用于非静态成员变量
3> auto不能定义数组

1.3 用到auto的场景

1> STL容器遍历

#include <string>

#include <iostream>
#include <map>
using namespace std;

int main()

	map<int, string>mp;
	mp.insert(make_pair(1, "Tom"));
	mp.insert(make_pair(2, "Mike"));
	mp.insert(make_pair(3, "Jack"));

	//for (std::iteraor it = mp.begin(); it != mp.end(); it++)
	for (auto it = mp.begin(); it != mp.end(); it++)
	
		cout << it->first << " " << it->second << endl;
	
	return 0;

2> 范式编程

#include <iostream>
#include <string>
using namespace std;

class T1

public:
	static int get()
	
		return 10;
	
;

class T2

public:
	static string get()
	
		return "hello world";
	
;


template<typename T,typename P>//不用auto
void func01()

	P ret = T::get();
	cout << ret << endl;


template<typename T>//用auto
void func()

	auto ret = T::get();
	cout << ret << endl;


int main()

	func<T1>();
	func<T2>();
	cout << "------------------------------" << endl;
	func01<T1, int>();
	func01<T2, string>();
	return 0;


2. decltype

在某些情况下,不需要或者不能定义变量,但是希望得到某种类型,这时候就可以使用 C++11 提供的 decltype 关键字了,它的作用是在编译器编译的时候推导出一个表达式的类型,语法格式如下:

decltype(表达式)

decltype 是 “declare type” 的缩写,意思是 “声明类型”。decltype 的推导是在编译期完成的,它只是用于表达式类型的推导,并不会计算表达式的值。
decltype 推导的表达式可简单可复杂,在这一点上 auto 是做不到的,auto 只能推导已初始化的变量类型。

2.1 decltype推到规则

分三种场景讨论decltype的推导规则:
1> 表达式为 普通变量/普通变量表达式/类表达式,这种情况使用decltype推导出的类型和表达式的类型一致

#include <iostream>
#include <string>
using namespace std;

class Test

public:
    string text;
    static const int value = 110;
;

int main()

    int x = 99;
    const int &y = x;
    decltype(x) a = x;
    decltype(y) b = x;
    decltype(Test::value) c = 0;

    Test t;
    decltype(t.text) d = "hello, world";

    return 0;

解析如下:

变量 a 被推导为 int 类型
变量 b 被推导为 const int & 类型
变量 c 被推导为 const int 类型
变量 d 被推导为 string 类型

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

class Test...;
//函数声明
int func_int();                 // 返回值为 int
int& func_int_r();              // 返回值为 int&
int&& func_int_rr();            // 返回值为 int&&

const int func_cint();          // 返回值为 const int
const int& func_cint_r();       // 返回值为 const int&
const int&& func_cint_rr();     // 返回值为 const int&&

const Test func_ctest();        // 返回值为 const Test

//decltype类型推导
int n = 100;
decltype(func_int()) a = 0;		
decltype(func_int_r()) b = n;	
decltype(func_int_rr()) c = 0;	
decltype(func_cint())  d = 0;	
decltype(func_cint_r())  e = n;	
decltype(func_cint_rr()) f = 0;	
decltype(func_ctest()) g = Test();	

解析如下:

变量 a 被推导为 int 类型
变量 b 被推导为 int& 类型
变量 c 被推导为 int&& 类型
变量 d 被推导为 int 类型
变量 e 被推导为 const int & 类型
变量 f 被推导为 const int && 类型
变量 g 被推导为 const Test 类型

函数 func_cint () 返回的是一个纯右值(在表达式执行结束后不再存在的数据,也就是临时性的数据),对于纯右值而言,只有类类型可以携带const、volatile限定符,除此之外需要忽略掉这两个限定符,因此推导出的变量 d 的类型为 int 而不是 const int。
3> 表达式是一个左值,或者被括号 ( ) 包围,使用 decltype 推导出的是表达式类型的引用(如果有 const、volatile 限定符不能忽略)。

#include <iostream>
#include <vector>
using namespace std;

class Test

public:
    int num;
;

int main() 
    const Test obj;
    //带有括号的表达式
    decltype(obj.num) a = 0;
    decltype((obj.num)) b = a;
    //加法表达式
    int n = 0, m = 0;
    decltype(n + m) c = 0;
    decltype(n = n + m) d = n;
    return 0;

解析如下:

obj.num 为类的成员访问表达式,符合场景 1,因此 a 的类型为 int
obj.num 带有括号,符合场景 3,因此 b 的类型为 const int&。
n+m 得到一个右值,符合场景 1,因此 c 的类型为 int
n=n+m 得到一个左值 n,符合场景 3,因此 d 的类型为 int&

2.2 decltype的应用

关于 decltype 的应用多出现在泛型编程中。

3. decltype和auto的结合使用 — 返回类型后置语法

在泛型编程中,可能需要通过参数的运算来得到返回值的类型。

以上是关于C++ 11 auto 与 decltype的主要内容,如果未能解决你的问题,请参考以下文章

C++11新特性:3—— C++ decltype类型推导完全攻略

C++11新特性:3—— C++ decltype类型推导完全攻略

C++学习笔记——auto/decltype 自动推导类型

C++学习笔记——auto/decltype 自动推导类型

C++学习笔记——auto/decltype 自动推导类型

C++学习笔记——auto/decltype 自动推导类型