自动类型推导(C++11)

1.auto

1.1 auto自动推导

​ auto能自动推导变量的类型,但使用auto自动类型推导必须给变量初始化,不然无法推导。auto可以与指针、引用结合,也可以与const、volatile限定符配合使用。只有当变量是指针或者引用类型时,推导结果才会保留const,volatile关键字。

	int animal = 1024;
	auto cat = animal;//cat推导为int类型, auto对应int
	auto dog;//dog未被初始化, 不能被自动推导 **语法错误**
	auto* pet = &animal;//pet推导为int*, auto对应int
	const auto pig = animal;//pig为const int类型,auto对应int
	auto duck = pig;//duck为int类型 **pig是const int,但duck没有指针或引用,所以不保留const**
	const auto& horse = animal;//horse为const int类型
	auto& mouse = animal;//mouse为int&类型

​ auto一般适用于替代迭代器的定义和泛型编程中。

  • 如果变量的定义太冗长,可以用auto替代
vector<int>val{ 1,2,3 };
	auto it = val.begin();//vector<int>::iterator it,简化了很多
	for (;it != val.end();it++)
		cout << *it;
  • 在泛型编程中,如果要接收一个模板变量,是很难确定变量的类型,所以用什么数据类型接收就是一件非常头疼的事。解决这个问题,不仅要在模板声明中添加多个变量,在模板函数调用中还要多写多个参数。但如果有了auto关键字,就迎刃而解了。只需将不确定类型的变量用auto接收即可完成任务。
template <class T,class P>
T test1(T val) {
	P res = val;//不仅要添一个class P,调用时也要多传一个参数。
	return res;
}
template <class T>
T test2(T val) {
	auto res = val;//auto 定义res省去了很多工程
	return res;
}
int main() {
	cout << test1<int,int>(2);
	cout << test2<int>(2);
}

1.2 auto的限制

  • 不能在函数参数中使用
int test(auto a){ //*错误*
	return -1;
}
  • 不能用于初始化类的非静态成员变量

​ 又因为静态非常量成员不能在类内初始化,所以在类内auto只能修饰静态常量成员

class test {
public:
	auto a = -1;	//	*错误*
	static auto b = -1;	//	*错误* 静态非常量要在类外初始化
	static const auto c = 'c';

}
  • 不能定义数组
int arr[]={1,2,3};
auto suss=arr;//正确,arr1为int*类型
auto err1[]=arr;// *错误*
auto err2[]={1,2,3};// *错误*
  • 不能当作模板参数
template <typename T>
T test(T val) {
	return val;
}
int main() {
	cout << test<int>(2);//正确
	cout << test<auto>(2);// *错误*
	
}

2.decltype

语法格式:decltype(表达式)

在变量类型不确定又不想声明的情况下可以用到decltype。decltype对变量类型的推导是在编译期完成的,只用于表达式类型的推导而不计算表达式的值。

推导规则

  • 表达式为变量,推导得到的类型与变量类型一致

  • 表达式为函数,推导得出的类型与函数返回值一致

​ 如果const修饰的是纯右值(纯数据)时,const不会保留,比如const int类型会推导成int。

  • 左值表达式或者被括号修饰,推导结果为表达式类型的引用,如果有const、volatile是不能省略的。
	//括号修饰
	const int const_int = 10;
	int normal_int = 10;
	decltype((const_int)) v1= 3;//const int& v1
	decltype((normal_int)) v2= normal_int;//int& v2 
	//表达式修饰
	int m = 1, n = 2;
	decltype(m+n) v3 = 3;//int v3  m+n是右值
	decltype(n=m+n) v4 = normal_int;//int& v4	左值表达式推导结果为引用

decltype同auto一样,广泛应用于泛型编程中。比如说,写了个类模板,里面用到了容器,想用迭代器遍历容器中的数据,迭代器如何定义?如果用 T::iterator it; 之类的语法是错误的,因为编译器无法识别。最好的方案就是用decltype类型推导。

template <class T>
class Container
{
public:
    void func(T& c)
    {
        for (it = c.begin(); it != c.end(); ++it)
        {
            cout << *it << " ";
        }
        cout << endl;
    }
private:
    //T::iterator it;// *错误* 这里不能确定迭代器类型
    decltype(T().begin()) it;
};
   

总结一下,auto的使用必须初始化,decltype可以不用初始化。

3.融合!返回值类型后置

上述文章阐述了auto和decltype的用法,此处讲解一个两者结合的使用方法。

在设计模板函数或者模板类的时候,难免会出现模板变量类型不一样的情况。加入需要两个数值类型的加和运算的模板函数,返回两者的加和。我们知道数值类型有很多,short,int,float,double,long等等,甚至字符变量也能掺和掺和。不同的组合的返回类型也是不同的,但在设计模板函数时在一开头就要给出返回类型,在没有确定参数类型时给出返回类型似乎是一件不可能的事情,C++14中编译器才可以自己推导任何函数的返回类型,如果C++11的编译器用auto做函数返回类型是错误的,因为没有初始化。所以就想到了decltype,然而decltype的使用需要知道传递的参数,如果这么写

decltype(t+u) add(T t, U u)

肯定是错误的,因为decltype中的t和u还没给出,编译器无法识别直接报错。如果能让返回类型放在参数列表之后定义就好了。所以便有了下述的代码思路

template <class T,class U>
auto add0(T t, U u) -> decltype(t+u) 
{
    return t + u;
}

这就是返回值类型后置。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值