首页 > 编程语言 >[c++11新特性]02-自动类型推导

[c++11新特性]02-自动类型推导

时间:2022-12-06 11:00:25浏览次数:47  
标签:11 02 decltype 推导 int auto c++ 类型 const

自动类型推导

在c++11中,关于类型推导的关键字有 using,decltype,auto,typeid。

在c++11之前我们要声明一个类型的别名往往使用的是typedef,但是该关键字在模板类型推导中存在一些缺陷,如下:

  • 无法根据模板类型动态的进行类型推导(使用decltype解决)
  • 无法对模板的实例进行typedef(使用using解决)

先看下面的示例代码:

#include <iostream>
#include <vector>

template<class Container>
class Foo
{
public:
void func(Container &c)
{
m_it = c.begin();
}
private:
typename Container::iterator m_it;
};

template <typename T>
class MapString
{
public:
typedef std::map<std::string,T> type;
};

上面的代码演示了在c++11之前使用typedef为容器迭代器取别名,以及实例化std::map。调用代码如下:

Foo<std::vector<int>> f;
std::vector<int> data{1,2,3};
const std::vector<int> const_data{1,2,2};
f.func(data); // 合法
f.func(const_data); // 非法,因为 m_it 是一个非 const 的迭代器,而 const_data 的迭代器是 const 版本的

// 使用 MapString
MapString<int>::type stringInt; // 使用起来很别扭,无法直接使用 MapString

要解决上面的问题,在c++11之前需要为Foo提供const版本的特化版本,而MapString却没有好的解决办法。在c++11中这两个都可以使用 using 来解决。可以说能使用 typedef 的地方一定可以使用 using,而能使用using的不一定可以使用typedef。

using:更好的typedef

using 作用与typedef一样,用于声明一个类型的别名,但是它的语法更自然,适用范围更广,使用它定义一个新的类型就像定义一个变量一样简单自然。

using 在模板别名中的使用

template <typename T>
using StringMap = std::map<std::string,T>;

// 使用 StringMap
StringMap<int> v;

using 在函数指针中的使用

在传统的使用typedef声明一个函数指针类型的时候语法往往晦涩难懂,而使用using语句声明函数指针将更加清晰明了,对比如下:

typedef int(*func_t)(char *src,size_t len);
using func_t = int(*)(char *,size_t);

decltype:类型推导

decltype可以让编译器推导出一个表达式的类型,它比我们常用的typeof更加智能。它的使用很像sizeof,只不过一个用来计算对象的字节数,一个用来推导表达式的类型。示例使用如下:

std::map<std::string,int> coll;
decltype(coll)::value_type elm; // <--- decltype(coll)::value_type的类型是std::pair<std::string,int>,因此,elm的类型就是一个std::pair

One application of decltype is to declare return types (see below). Another is to use it in metaprogramming(seeSection5.4.1,page125)or to pass the typeof alambda(seeSection10.3.4,page504).

使用decltype进行类型推导

文章开头介绍的Foo不得不为const的容器提供特化版本,如果使用decltype则可以减少程序员的重复工作,使用decltype版本的代码如下:

template <typename Containor>
class Goo
{
public:
void func(Containor &c)
{
m_it = c.begin();
}
private:
decltype(Containor().begin()) m_it;// 关键
};

int main(int argc,char **argv)
{
Goo<std::vector<int>> g;
Goo<const std::vector<int>> cg;
std::vector<int> data{1,2,3};
const std::vector<int> const_data{1,2,2};
g.func(data); // 合法
cg.func(const_data); // 合法,推导出的 m_it 类型为 const_iterator
return 0;
}

上面的关键代码为decltype那一行,它先定义一个匿名的Containor对象,然后获取其begin()迭代器,之后使用decltype推导出其容器的迭代器类型。

decltype的功能是在编译时推导出一个表达式的类型,其语法如下:

decltype(exp)

由于decltype接受的是一个表达式,这给类型推导很大的自由。

decltype 的推导规则

  • 如果exp是类型、标识符,则推导的类型与exp一致
  • 如果exp是函数调用,则其推导类型与函数返回类型一致
  • 若exp是一个左值,则其推导类型是exp类型的左值引用;否则和exp类型一致
int &func_int_l();
int &&func_int_rr();
int func_int();


int x;
decltype(x) al = x;

// 《深入应用C++11》 page11

auto:新的意义

auto 示例

// AUTO的示例
auto x = 5; // x 是 int 类型
auto pi = new auto(x); //
const auto *v = &x,u = 6; // 这里的 u = 6 是一定要进行赋值的,否则u仍旧会报错,虽然前面经过推导auto 的类型为int。同时,如果写成u=6.0编译器也会报错,因为和前面auto推导出的类型冲突

/*AUTO的推导规则*/
int x = 0;

auto *a = &x; // a --> int *
auto b = &x; // b --> int *
auto &c = x; // c --> int &
auto d = c; // d --> int

const auto e = x; // e --> const int
auto f = e; // f --> int
const auto & g = x; // g --> const int &
auto & h = g; // h --> const int &
  • auto 声明的变量必须立马初始化,可以把auto看成一个占位符,变量的类型由编译器在编译期确定
  • auto 在类中只能修饰静态变量,不能修饰成员变量
  • 如果使用auto在一条语句中定义多个变量,则这些变量的类型必须保持一致性
  • 由f的推导,可知当表达式带有const的时候,auto会把const属性抛弃掉,推导成 none-const 类型
  • 由 h 的推导可知,当 auto 和 引用(或者指针)结合时,auto的推导将保留 const 属性

auto 的限制

  • auto 不能用于函数参数
  • auto 不能用于类的非静态成员变量auto 无法定义数据
  • auto 无法推导出模板类型,不可以作为模板的类型入,std::vector*<auto>* vec{1,2,3};

auto 的使用场景

auto 虽好,不要滥用!!!以下为auto建议的使用场景:

  • 定义简单的类型,或者复杂的类型作为返回值时使用auto进行推导
  • 遍历容器的时候使用auto替代迭代器
  • 定义lambda表达式的时候

后置类型推导—— auto 和 decltype 在函数返回值中的应用

除了用来定义对象,decltype还可以在函数定义中使用,它可以通过一个表达式的类型来自动推导出函数的返回类型,如下:

template <typename T1, typename T2>
auto add(T1 x, T2 y) -> decltype(x+y)
{
return x + y;
}

template<class T>
T &foo(T &t)
{
return t + 1;
}


auto add(T &val) -> decltype(foo(val))
{
return foo(val);
}

标签:11,02,decltype,推导,int,auto,c++,类型,const
From: https://blog.51cto.com/u_6650004/5915178

相关文章