14-2(C++11)类型推导、类型计算
- 类型推导
- auto关键字
- auto类型推断本质
- auto与引用 联用
- auto关键字的使用限制
- 类型计算
- 类型计算分类
- 与类型推导相比
- 四种类型计算的规则
- 返回值后置
类型推导
auto关键字
- C++98中,auto表示栈变量,通常省略不写
- C++11中,给auto赋予新的语义,表示自动类型推导
- 既根据对变量进行初始化时所使用的数据的类型,由编译器自动推导出所定义变量的实际类型
- 既根据对变量进行初始化时所使用的数据的类型,由编译器自动推导出所定义变量的实际类型
auto类型推断本质
- 按照定义独立对象并根据初始化数据的类型进行推导
- 无法自动推断 const,只能在auto的上下文显示指明
- 如果给出的 初始化数据类型为常量指针,则可以自动推导const
// 类型推导不是类型照抄
#include <iostream>
#include <typeinfo>
using namespace std;int main( void ){int a = 10;const int b = 10;auto c = a;// auto: int c: intcout << "c的类型:" << typeid(c).name() << endl; // icout << "&c: " << &c << ", &a: " << &a << endl; // 地址不同c++; // 允许更改auto d = b;// auto: int d: intcout << "d的类型:" << typeid(d).name() << endl; // icout << "&d: " << &d << ", &b: " << &b << endl; // 地址不同d++; // 允许更改const auto e = b;// auto: int e: const intcout << "e的类型:" << typeid(e).name() << endl; // icout << "&e: " << &e << ", &b: " << &b << endl; // 地址不同
// e++; // 不允许更改auto f = &b; // 如果初始化数据的类型是常量指针,则可以自动推导const(第一种可以自动推导const的情况)// auto: const int* f: const int*cout << "f的类型:" << typeid(f).name() << endl; // PKi
// *f = 666;f = NULL;return 0;
}
auto与引用 联用
- 按照定义独立对象并根据初始化数据的类型进行推导,所以不可能推导出引用
- 除非auto的上下文指明按照引用推导
- 若指明按引用推导并且目标带有常属性,则可以自动推导const
// 类型推导和引用联用
#include <iostream>
#include <typeinfo>
using namespace std;int main( void ){int a = 10;const int b = 10;auto c = a;// auto: int c: intcout << "c的类型:" << typeid(c).name() << endl; // icout << "&c: " << &c << ", &a: " << &a << endl; // 地址不同c++; // 允许更改auto& d = a;// auto: int d: int&cout << "d的类型:" << typeid(d).name() << endl; // icout << "&d: " << &d << ", &a: " << &a << endl; // 地址相同d++; // 允许更改auto& e = b; // 如果指明按引用推导,并且目标带有常属性,则也可以自动推导出const(这是第二种自动推导出const的情况)// auto: const int e: const int&cout << "e的类型:" << typeid(e).name() << endl; // icout << "&e: " << &e << ", &b: " << &b << endl; // 地址相同
// e++; // 不允许更改return 0;
}
auto关键字的使用限制
- 函数形参类型无法推导(C++14标准支持)
- 类的成员变量无法推导
// 类型推导的局限性
#include <iostream>
#include <typeinfo>
using namespace std;
/*
void foo(auto v){// ...
}
*/
/*
class A{
public:auto a; // 声明auto b; // 声明
};
*/int main( void ){
// foo(10);
// foo(3.14);return 0;
}
类型计算
类型计算分类
- C语言: sizeof - 计算类型的大小
- C++语言: typeid - 可以获取类型的信息字符串
- C++11: decltype - 获取参数表达式的类型
注意事项:类型计算由编译器确定,并不是运行期确定
与类型推导相比
- 对类型的确定更加精准
const int a = 10;
auto b = a; // b类型推导为int
decltype(a) c = a; //c类型计算为 const int
- 可以做到类型相同但值不同
const int a = 10:
auto b=a;
decltype(a) c = 100;
// 类型推导和类型计算的比较
#include <iostream>
#include <typeinfo>
using namespace std;int main( void ){const int a = 10;auto b = a;// auto : int b : intcout << "b的类型:" << typeid(b).name() << endl; // icout << "&b: " << &b << ", &a:" << &a << endl; // 地址不同b++; // 允许更改// 类型计算比类型推导在类型的确定上会更加精准decltype(a) c = 666;// = a;// c: const intcout << "c的类型:" << typeid(c).name() << endl; // i cout << "&c: " << &c << ", &a:" << &a << endl; // 地址不同
// c++; // 不允许更改return 0;
}
四种类型计算的规则
- 标识符表达式,直接取表达式的类型
- 函数表达式,取函数返回值的类型
- 其他表达式
- 如果表达式的值为左值,则取左值引用的类型
- 如果表达式的值为右值,则取该右值本身的类型
// 四种类型计算的规则
#include <iostream>
#include <typeinfo>
using namespace std;double foo();int main( void ){int a = 10;// 如果给decltype传递的是标识符表达式,则编译器根据标识符的类型,作为最终计算出的类型decltype(a) c = a;// c: intcout << "c的类型:" << typeid(c).name() << endl; // icout << "&c:" << &c << ", &a:" << &a << endl; // 地址不同c++; // 允许更改// 如果给decltype传递的是函数表达式,则编译器根据函数的返回值的类型,作为最终计算出的类型decltype(foo()) d = a;// d: doublecout << "d的类型:" << typeid(d).name() << endl; // dcout << "&d:" << &d << ", &a:" << &a << endl; // 地址不同d++; // 允许更改// 如果是其它表达式,并且表达式结果为左值,则编译器取该左值引用的类型,作为最终计算出的类型decltype(++a) e = a;// e: int&cout << "e的类型:" << typeid(e).name() << endl; // icout << "&e:" << &e << ", &a:" << &a << endl; // 地址相同e++; // 允许更改// 如果是其它表达式,并且表达式结果为右值,则编译器取该右值本身的类型,做为最终计算出的类型decltype(a++) f = a;// f: intcout << "f的类型:" << typeid(f).name() << endl; // icout << "&f:" << &f << ", &a:" << &a << endl; // 地址不同f++; // 允许更改 return 0;
}
返回值后置
auto 函数名 (形参表) ->decltype(表达式)
#include <iostream>
#include <typeinfo>
using namespace std;auto foo(int x, double y) -> decltype(x+y){return x + y;
}int main( void ){auto f = foo(3,3.14);cout << "f的类型:" << typeid(f).name() << endl;return 0;
}