[Effective modern cpp] 第一章 类型推导

模板类型推导

模板的定义:

	template <typename T>
	func(ParamType args)

(1)类型推导Param包含普通的引用或指针的情况

    template <typename T>
    func(T& args)

	const int& exp = 10func(exp); //Param类型为 const int&
			   //T类型为const int
	
	const int exp = 10;
	func(exp);//Param类型为 const int&
			  //T类型为const int
	int exp = 10;
	func(exp);//Param类型为 int&
			  //T类型为int

Note:
1、推导结果会忽略exp的引用或指针,然后根据忽略引用或指针特性的exp去推导T。
2、同时保留exp的CV特性(即const、violatile)。

(2)类型推导Param为万能引用的情况

  template <typename T>
  func(T&& args)
  
  const int exp = 10;
  func(exp);//Param类型为const int&
  			//T类型为const int&

  const int& exp = 10;
  func(exp);//Param类型为const int&
  			//T类型为const int&

  int exp = 10;
  func(exp);//Param类型为int&
      		//T类型为int&
      		
  func(10);//Param类型为int&&
  		   //T类型为int

Note:
1、左值被推导为左值引用,如果是右值则按照(1)种的法则进行。
2、在模板类型中,T唯一被推导成引用类型。这里有个小细节,上面模板前3种情况下模板
实例化的结果如下所示:

    func(int& && args);

在C++是不允许有对引用进行引用,因此这里涉及到一个机制,引用的折叠(模板实例化是是其中之一)。

(3)类型推导Param为既不是引用也不是指针的情况

  template <typename T>
  func(T args) //args pass-by-value
  
  const int exp = 10;
  func(exp);//Param类型为int
  			//T类型为int&

  const int& exp = 10;
  func(exp);//Param类型为int
  			//T类型为int

  int exp = 10;
  func(exp);//Param类型为int
      		//T类型为int
      		
  func(10);//Param类型为int
  		   //T类型为int

Note:这里模板实例化的机制是实参通过拷贝的形式传递给args,即此时实参与形参是不用的对象。因此存在以下两条规则:
1、如果exp包含CV特性,则忽略exp的CV特性
2、同理exp是引用类型,则忽略exp的CV特性

corn case(指向const内容的const指针)

  template <typename T>
  func(T args) //args pass-by-value
  
  const char* const names= "Xiao Wang";
  func(names);//Param类型为 const char* 
  			  //T类型为 const char*
  			  

Note:这里nams是一个指向const字符串的const指针。当传递给func时,由于对这个const指针进行拷贝操作,这个指针的内存bit被拷贝给param,因此指针的const被忽略,而字符串的const保留下来。

corn case (数组退化、函数退化)

  template <typename T>
  func(T args) //args pass-by-value
  
  const char names[10]= "Xiao Wang";//类型为 const char[]
  func(names);//Param类型为 const char* 
  			  //T类型为 const char*
  			  
  void somefunc(int,double);

  func(somefunc); //Param类型为 void (*)(int,double)

Note: names的类型为const char[],然而在类型推导过程中退化成指针const char*。同理函数也会退化成函数指针。

  template <typename T>
  func(T& args) //参数按照引用传递
  
  const char names[10]= "Xiao Wang";//类型为 const char[]
  func(names);//Param类型为 const char (&)[10]
  			  //T类型为 const char (&)[10]
  			  
  void somefunc(int,double);

  func(somefunc); //Param类型为 void (&)(int,double)

auto类型推导

  auto x = {10,5,6}; //x的类型 std::initializer_list
  
  template <typename T>
  void func(T args);

  func({10,5,6});//编译器无法推导类型

Note:
auto类型推导与模板类型推导类似,除了针对花括号初始化成std::initializer_list,但是模板类型不能通过编译。

template <typename T>
auto func(Param args);

Note:在c++14中,auto作为函数或lambda返回类型,类型推导机制与模板类型推导一致。

decltype的理解

用法:给定变量或表达式,decltype会告诉变量或表达式的类型。
推导四个规则:decltype(e)
1、如果e是不带括号的标记符表达式或类成员表达式,推导结果是e所命名实体的类型。如果e是一个重载的函数,则编译错误。(标记符表达式是除去关键字、字面量等编译器需要使用的标记之外的程序员自己定义的标记,而单个标记符对应的表达式即为标记符表达式。)
2、如果e是个将亡值,则推导为T&&。
3、如果e是个左值,则推导为T&。
4、如果e是个纯右值,则推导为T。
场景应用:假设我们想写一个函数,这个函数中接受一个支持方括号索引(也就是"[]")的容器作为参数,验证用户的合法性后返回索引结果。这个函数的返回类型与函数参数有关,则可以通过c++11尾随返回类型技术,如下所示:

  template <typename container,typename T>
  auto func(container& c,T i) -> decltype(c[i]){
  	...
  	return c[i];
  }

在c++14中,上述可以去掉尾随返回类型,直接用auto进行表示:

  template <typename container,typename T>
  auto func(container& c,T i){
  	...
  	return c[i];
  }

然而这样的代码又要引发新的问题,由于对于大多数容器进行[]操作,都会返回**T&**类型,而auto在函数返回类型推导与模板推导一致,因此上述代码会忽略引用特性,使得返回一个右值。

  std::deque<int> d;
  ....
  func(d,5) = 10;//我们希望修改d[5]的值,然而函数返回右值,导致编译错误

为了达到我们预期的效果,我们需要将返回值运用decltype方法,即func()返回的类型是d[i]的类型。因此可以利用decltype(auto)形式,使得auto推导类型应用decltype规则。
在应用decltype(auto)时,应注意在返回值添加()会导致意想不到的结果。

    decltype(auto) f1()
    {
      int x = 0;
      ...
      return x;        // decltype(x) is int, so f1 returns int
    }

    decltype(auto) f2()
    {
      int x = 0;
      return (x);     // decltype((x)) is int&, so f2 return int&
    }

获得类型推导结果

编译器诊断

声明一个类模板,但不提供实现。

int a;
const int * b;
template <typename T>
class TD;//模板没有写相关实现。

TD<decltype(a)> test1;
TD<decltype(b)> test2;

编译报错结果:

error: aggregate 'TD<int> xType' has incomplete type and cannot be defined
error: aggregate 'TD<const int *> yType' has incomplete type and cannot be defined
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值