我是靠谱客的博主 单身春天,最近开发中收集的这篇文章主要介绍c++11/14新特性解读之五 (auto,decltype 类型推导),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

在介绍类型推导之前,首先介绍下typeid,c++的运行时类型识别(RTTI)机制是为每个类型产生type_info类型的数据,typeid就会返回变量相应的type_info数据。type_info的name成员函数可以返回类型的名字,hash_code成员函数返回该类型唯一的哈希值,以供程序员对变量的类型随时进行比较。

class A {};
class B {};
struct C {};

int main()
{
 int i;
 A a1;
 A a2;
 B b;
 C c;
 cout << typeid(i).name() << endl;
 cout << typeid(a1).name() << endl;
 cout << typeid(a1).hash_code() << endl;
 cout << typeid(a2).hash_code() << endl;
 cout << typeid(b).hash_code() << endl;
 return 0;
}

输出结果:
int
class A
1201377968
1201377968
2199077265
可见a1和a2的类型的哈希值一致,因为他们都是class A的对象。

auto,decltype类型推导
c++11将类型推导标准化为auto以及decltype,auto是从变量声明的初始化表达式获得变量类型,与auto不同的是decltype总是以一个普通表达式为参数,返回该表达式的类型。例如:

double foo()
{
 return 1.0;
}

int main()
{
 auto x = 1;
 cout << typeid(x).name() << endl; // int
 
 auto y = foo();
 cout << typeid(y).name() << endl; // double

 std::vector<int> vecList;
 auto iter = vecList.begin(); 
 cout << typeid(iter ).name() << endl; // std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<int> > >
 
 struct MyStruct
 {
  int i = 0;
 };
 struct MyStruct str;
 auto str1 = str;
 cout << typeid(str1).name() << endl; // struct `int __cdecl main(void)'::`2'::MyStruct

 // auto z; 编译器报错,无法推导,声明时必须初始化
 // z = x;

 int i;
 decltype(i) j = 0;
 cout << typeid(j).name() << endl; // int

 float a;
 double b;
 decltype(a + b) c;
 cout << typeid(c).name() << endl; // double

 typedef decltype(vecList.begin()) vectype;
 vectype type;
 cout << typeid(type).name() << endl;

 return 0;
}

输出结果:
int
double
class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types > >
struct int __cdecl main(void)'::2’::MyStruct
int
double
class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types > >

在代码清单中,可以看到,
auto“声明” z,但不立即对其进行定义,此时编译器会报错。auto声明必须被初始化,以使编译器能够从初始化表达式中推导出其类型。
decltype是返回其表达式的类型。

auto使用细则:
1、将变量x的指针赋给auto声明的变量,使用auto或auto*并没有什么区别,但是将变量x的引用赋给auto声明的变量,必须声明为auto&。例如:

int main()
{
 int x;
 auto a = &x;
 auto *b = &x;  // a == b
 cout << "a:" << a << " b:" << b << endl;
 
 auto c = x;
 auto& d = x; // &c != &d
 cout << "&c:" << &c << " &d:" << &d << endl;
}

输出结果:
a:00AFF7CC b:00AFF7CC
&c:00AFF7CC &d:00AFF79C

2、将一个被const或volatile(简称cv限定符)修饰的变量赋给auto声明的变量,auto声明的变量不会带走cv修饰,而引用可以。例如:

const int x = 1;
auto a = x;
auto& b = x;
a = 2;
b = 2; // 编译报错,因为b被const修饰,不能修改

3、在同一个赋值语句中,auto声明多个变量的类型,这些变量的类型必须相同,否则编译报错。例如:

int x;
int y;
float z;
auto a = x,b=y;
auto c = x,d = y,e = z; // 编译器报错,e与c,d类型不同

4、auto不能推导的情况:
a. auto不能声明函数的形参,如: int fun(auto x)会编译报错;
b. 对于结构体来说,非静态成员的类型不能为auto,即使设置了初始值也不行,编译器阻止了auto对结构体非静态成员的推导。 例如:struct str{ auto var = 10;};会编译报错。
c. 声明auto数组 .例如 auto a[3]; 编译器会报错
d. 实例化模板的时候使用auto作为模板参数。例如vector v; 会报错。

decltype推导四规则:
1、如果e是一个没有带()的表达式,或者类成员访问表达式,那么decltype(e)就是e所命名的实体类型,此外,如果e是一个被重载的函数,则会导致编译时错误。
2、否则,假设e的类型是T,如果e是一个将亡值,那么decltype(e)为T&&。
3、否则,假设e的类型是T,如果e是一个左值,则decltype(e)为T&。
4、否则,假设e的类型是T,则decltype(e)为T。

例如:

int i= 4int arr[5] = {0};
int *ptr = arr;
struct S {double d;} s;
void Overloaded(int);
void Overloaded(char);
int && RvalRef();
const bool Func(int);
// 规则一
decltype(arr) var1; // int[5]
decltype(ptr) var2; // int*
decltype(s.d) var3; // double
//decltype(Overloaded) var5 // 编译失败,是个重载函数
// 规则二
decltype(RevalRef()) var6 = 1; // int&&
// 规则三
decltype(true?i:i) var7 = i; // int&,三元运算符,返回一个i的左值
decltype((i)) var8 = i; // int&,带圆括号的左值
decltype(++i) var9 = i; // int&,++i返回i左值
decltype(arr[3]) var10 = i; // int&,[]操作返回左值
decltype(*ptr) var11 = i; // int&,*操作返回左值
decltype("lvar") var12 = "lvar"; // const char&[9],字符串常量为左值
//规则四
decltype(1) var13; // int,除字符串外为右值
decltype(i++) var14; // int,i++返回右值
decltype(Func(1)) var15; // const bool,圆括号可以忽略。

另外,与auto不同,decltype是能够带走cv限制符的,不过,如果对象的定义中有const或volatile限制符,使用decltype推导时,其成员不会继承const或volatile。例如:

const int a = 0;
volatile int b;
struct S{int i;};
const S d;
cout << is_const<decltype(a)>::value <<endl;// 1
cout << is_volatile<decltype(b)>::value <<endl; // 1
cout << is_const<decltype(d.i)>::value <<endl; // 0,成员不是const

is_const和is_volatile是检查类型是否是常量还是易失的。

追踪返回类型
语法:
template<typename T1,typename T2>
auto sum(T1& t1, T2& t2) -> decltype(t1+t2)
{
return t1 + t2;
}

复合符号-> decltype(t1+t2)被称为追踪返回类型。

最后

以上就是单身春天为你收集整理的c++11/14新特性解读之五 (auto,decltype 类型推导)的全部内容,希望文章能够帮你解决c++11/14新特性解读之五 (auto,decltype 类型推导)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部