C++11/14新特性--类型推导 auto、decltype


一、概要

在传统 C 和 C++中,参数的类型都必须明确定义,这其实对我们快速进行编码没有任何帮助,尤其是当我们面对一大堆复杂的模板类型时,必须明确的指出变量的类型才能进行后续的编码,这不仅拖慢我们的开发效率,也让代码变得又臭又长。

C++11 引入了 auto 和 decltype 这两个关键字实现了类型推导,让编译器来操心变量的类型。这使得 C++ 也具有了和其他现代编程语言一样,某种意义上提供了无需操心变量类型的使用习惯。


二、auto

auto 在很早以前就已经进入了 C++,但是它始终作为一个存储类型的指示符存在,与 register并存。在传统 C++ 中,如果一个变量没有声明为 register变量,将自动被视为一个auto变量。而随着register被弃用,对 auto 的语义变更也就非常自然了。

使用 auto进行类型推导的一个最为常见而且显著的例子就是迭代器。在以前我们需要这样来书写一个迭代器:
for(vector::const_iterator itr = vec.cbegin(); itr != vec.cend(); ++itr)

有了auto之后可以:
for(auto itr = vec.cbegin(); itr != vec.cend(); ++itr); // itr 被推导为 vector::const_iterator 类型
auto i = 5; // i 被推导为 int
auto arr = new auto(10) // arr 被推导为 int *

注意:auto不能用于函数传参,不能用于推导数组类型。

 int main()
 {
	 auto i = 5;
	 int arr[10] = {0};
	 auto auto_arr = arr;
	 auto auto_arr2[10] = arr;  //编译报错
	
	 return 0;
 }


三、decltype

decltype操作符的值是一个类型,可用于其它对象的声明。
decltype 关键字是为了解决 auto关键字只能对变量进行类型推导的缺陷而出现的。它的用法和sizeof 很相似:

decltype(表达式)


计算某个表达式的类型,如:

auto x = 1;
auto y = 2;
decltype(x+y) z;

注意:注意:decltype((variable))(注意是双层括号)的结果永远是引用,而decltype(variable)的结果只有当variable本身是一个引用时才是引用


decltype与auto都可以用来推断类型,但是二者有几处明显的差异
1)auto忽略顶层const,decltype保留顶层const。
2)对引用操作,auto推断出原有类型,decltype推断出引用。
3) 对解引用操作,auto推断出原有类型,decltype推断出引用。
4)auto推断时会实际执行,decltype不会执行,只做分析。总之在使用过程中和const、引用和指针结合时需要特别小心。


1. decltype用法
1)基本用法

int getSize() { return 0; };

int main(void)
{
	int tempA = 2;

	//1.dclTempA为int
	decltype(tempA) dclTempA;
	dclTempA = 10;

	//2.dclTempB为int,对于getSize根本没有定义,但是程序依旧正常,因为decltype只做分析,并不调用getSize().
	decltype(getSize()) dclTempB;
	dclTempB = 11;

	//3.dcltempC为string
	string tempC = "abc";
	decltype(tempC) dcltempC;
	dcltempC = "efg";
	return 0;
}

在这里插入图片描述


2)与const结合

int main(void)
{
	double tempA = 3.0;
	const double ctempA = 5.0;
	const double ctempB = 6.0;
    const double *const cptrTempA = &ctempA;

	  
	//1.dclTempA推断为const double(保留顶层const,此处与auto不同)
	decltype(ctempA) dclTempA = 4.1;

	//2.dclTempA为const double,不能对其赋值,编译不过
	dclTempA = 5;

	//3.dclTempB推断为const double * const
	decltype(cptrTempA) dclTempB = &ctempA;

	//4.输出为4(32位计算机)和5*/
	cout << sizeof(dclTempB) << "    " << *dclTempB << endl;

	//5.保留顶层const,不能修改指针指向的对象,编译不过
	dclTempB = &ctempB;

	//6.保留底层const,不能修改指针指向的对象的值,编译不过
	*dclTempB = 7.0;

	return 0;
}


3)与引用结合

int main(void)
{
	int tempA = 0, &refTempA = tempA;

	//1.dclTempA为引用,绑定到tempA
	decltype(refTempA) dclTempA = tempA;

	//2.dclTempB为引用,必须绑定到变量,编译不过
	decltype(refTempA) dclTempB = 0;

	//3.dclTempC为引用,必须初始化,编译不过
	decltype(refTempA) dclTempC;

	//4.双层括号表示引用,dclTempD为引用,绑定到tempA
	decltype((tempA)) dclTempD = tempA;

	const int ctempA = 1, &crefTempA = ctempA;

	//5.dclTempE为常量引用,可以绑定到普通变量tempA
	decltype(crefTempA) dclTempE = tempA;

	//6.dclTempF为常量引用,可以绑定到常量ctempA
	decltype(crefTempA) dclTempF = ctempA;

	//7.dclTempG为常量引用,绑定到一个临时变量
	decltype(crefTempA) dclTempG = 0;

	//8.dclTempH为常量引用,必须初始化,编译不过
	decltype(crefTempA) dclTempH;

	//9.双层括号表示引用,dclTempI为常量引用,可以绑定到普通变量tempA
	decltype((ctempA))  dclTempI = ctempA;

	return 0;
}


4)与指针结合

int main(void)
{
	int tempA = 2;

	int *ptrTempA = &tempA;

	//1.常规使用dclTempA为一个int *的指针
	decltype(ptrTempA) dclTempA;

	//2.需要特别注意,表达式内容为解引用操作,dclTempB为一个引用,引用必须初始化,故编译不过
	decltype(*ptrTempA) dclTempB;

	return 0;
}


2. 什么时候使用decltype?

#include <iostream>
#include <string>
#include <stdio.h>
#include <vector>
#include <list>
#include <map>
using namespace std;


template<typename C>

void print(C& c)
{
	for (decltype (c.begin()) it = c.begin(); it != c.end(); ++it)
		cout << *it << ' ';

	cout << endl;
}

int main(void)
{
	int ai[] = { 10, 20, 30,40, 50 };
	vector<int> vi(ai, ai + 5);

	print(vi);

	list<int> const li(vi.begin(), vi.end());
	print(li);

	map<string, vector<int>> msv;
	msv["张飞"].push_back(70);
	msv["张飞"].push_back(85);
	msv["赵云"].push_back(75);
	msv["赵云"].push_back(90);
	msv["关羽"].push_back(80);
	msv["关羽"].push_back(95);

	// 此处省略15000行代码

	//   int sum = 0;

   //key_type就表示map中key的类型,value_type表示具体值的类型,mapped_type表示map中value(pair)的类型
	decltype (msv)::mapped_type::value_type sum = 0;
	for (size_t i = 0; i < msv["张飞"].size();++i)
		sum += msv["张飞"][i];
	cout << sum << endl;
	return 0;
}


3. auto和decltype结合使用,返回类型后置

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


double foo(int arg)
{
	return arg / 2.0;
}

int foo(double arg)
{
	return int(arg * 2);
}

// 返回类型后置
template<typename T>
auto bar(T const&arg) -> decltype (foo(arg))
{
	return foo(arg);
}

// 返回类型后置
template<typename T>
auto add(T const&x, T const& y) -> decltype (x + y)
{
	return x + y;
}



class Point

{
public:

	Point(int x, int y) : m_x(x), m_y(y) {}
	void draw(void) const
	{
		cout << "点(" << m_x << ',' << m_y << ')' << endl;
	}

private:
	int m_x, m_y;
};



class Line
{
public:

   Line(Point const& p1, Point const&p2) :m_p1(p1), m_p2(p2) {}

	void draw(void) const
	{
	   cout << "线(" << '\t';m_p1.draw();
	   cout << '\t';
	   m_p2.draw();
	   cout << ')' << endl;
	}

private:
   Point m_p1, m_p2;
};



Line const operator+ (Point const& p1, Point const&p2)
{
	return Line(p1, p2);
}

int main(void)

{
	cout << bar(1) << endl; // 0.5
	cout << bar(0.5) << endl; // 1

	Point p1(100, 200), p2(300, 400);

	Line line = add(p1, p2);
	line.draw();

	return 0;
}

结果输出:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值