新特性 - 类型推导

说明

  • 类似于动态语言,C++11支持自动类型推导。

auto

  • auto在早期C++中的标识临时变量,由于使用极少且多余,在C++11中已被用作类型推导使用。
  • auto自动类型推断,用于从初始化表达式中推断出变量的数据类型,可以简化我们的编程工作。

使用

map<int, map<int,int> > map;
map<int, map<int,int>>::const_iterator itr1 = map.begin();
const auto itr2 = map.begin();

auto i = 1;

注意项

  1. auto声明的变量必须初始化,这样编译期才能从初始化代码中推导出返回类型。
  2. 使用auto就不能在定义数据类型。
  3. auto是一个推导关键词,并不是一个数据类型,因此不能用于类型转换或其他一些操作,如sizeof和typeid。
  4. 推导不同数据类型必须独立开了,不能写在一起,例如:
auto x1 = 5, x2 = 5.0, x3='r'; //错误使用
  1. auto不能自动推导成CV-qualifiers(constant & volatile qualifiers),除非被声明为引用类型,如下:
const int i = 100;
auto j = i; //错误用法
auto &k = i; //正确用法
  1. auto会退化成指向数组的指针,除非被声明为引用
int a[9];
auto j = a;
cout<<typeid(j).name()<<endl; // This will print int*
 
auto& k = a;
cout<<typeid(k).name()<<endl; // This will print int [9]
  1. 如果初始化表达式是引用,则去除引用语义
int a = 10;
int &b = a;

auto c = b;//c的类型为int而非int&(去除引用)
auto &d = b;//d的类型才为int&

decltype

  • auto除了自动推导出数据类型还必须使用表达式的值去初始化变量,有时候只需要获取表达式的返回类型,这时该使用decltype,在推导过程中,编译器只是分析表达式并获取它的类型,却不进行实际的计算表达式的值。
  • 例子:
decltype(f()) sum;//sum的类型就是函数f的返回值类型。

注意项

  1. decltype在处理const和引用的方式与auto有些许不同,如果decltype使用的表达式是一个变量,则decltype返回该变量的类型(包括const和引用在内),如下:
const int ci = 42, &cj = ci;
 
decltype(ci) x = 0;   // x 类型为const int
auto z = ci;          // z 类型为int
 
decltype(cj) y = x;   // y 类型为const int&
auto h = cj;          // h 类型为int

declval

  • decltype 可以推导出表达式的数据类型,但是某些情况下,例如:类的成员函数,如果没有对象,成员函数无法调用,自然无法推导,而declval就是解决这种情况下的自动推导,在推导过程中,declval不需要构造实例。

使用

  • 声明
template<class T>
typename std::add_rvalue_reference<T>::type declval() noexcept;
  • 使用
#include <utility>
#include <iostream>

class Default { 
    int foo() const { return 1; } 
};

class NonDefault{
    NonDefault(const NonDefault&) { }
    int foo() const { return 1; }
};

int main()
{
    decltype(Default().foo()) n1 = 1;                   // type of n1 is int
    decltype(NonDefault().foo()) n2 = n1;               // 错误: NonDefault没有默认的构造函数
    decltype(std::declval<NonDefault>().foo()) n2 = n1; // 正确使用
}

auto和decltype配合使用

  • auto 占位,如下:
template<class T, class U>
??? mul(T x, U y){
    return x*y;
}
  • 这种情况下问号处最好能使用自动推导,正常使用应该为:
decltype(x*y)
  • 但是由于x和y都是后面传入的,因此可以使用以下替代
decltype(*(T*)(0)  *  *(U*)(0))
  • 整体写法如下:
template<class T, class U>
decltype(*(T*)(0)  *  *(U*)(0)) mul(T x, U y){
    return x*y;
}
  • 为了避免使用这种难看的写法,C++使用auto来占位,如下写法就可以:
template<class T, class U>
auto mul(T x, U y) -> decltype(x*y) {
    return x*y;
}
  • C++14 直接改成:
template<class T, class U>
auto mul(T x, U y){
    return x*y;
}

auto与decltype的区别

  1. auto 关注的是表达式返回值的数据类型,而decltype关注的是表达式本身的数据类型。
  2. auto忽略顶层const,decltype保留顶层const。
  3. 对引用操作,auto推断出原有类型,decltype推断出引用。
  4. 对解引用操作,auto推断出原有类型,decltype推断出引用。
  5. auto推断时会实际执行,decltype不会执行,只做分析。
  • 在使用中过程中和const、引用和指针结合时需要特别注意两者的区别。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章