C++万能引用

类型区别基本概念

template<typename T>
void func(const T&abc){}

  编译器推导T的类型,不仅仅看调用func(10)给的实参10的类型,还看形参abc的类型

万能引用的模板表现形式

template<typename T>
void func(T&& a){}

  如果我们给func传递了左值,那么万能引用就变成了左值引用;如果我们给func传递了右值,那么万能引用就变成了右值引用
  注意:T&&才是万能引用,T不是万能引用

万能引用资格的剥夺与辨认

  (1)剥夺:const修饰词会剥夺一个引用成为万能引用的资格,会被打回原型成为右值引用
  例:

template<typename T>
void func(const T&&a){}  

  注意:此时a的类型就是右值引用
  (2)辨认

template<typename T>
class MyTest{
   void my_func(T&& a){}
   template<typename T2>
   void func2_my(T2&& b){}
}

  注意:&MyTest::my_func并没有类型的推断,类型推断发生在MyTest类实例化时,所有my_func的形参a的类型是右值引用,而不是万能引用。而func2_my有类型的推断,所以,func2_my的形参b的类型是万能引用

如何推导编译器推断的类型

template<typename T>
void my_func(T& tmprv){}
int i = 18;
const int j = i;
const int& k=i; 

  如果tmprv类型是个指针或引用(但不是万能引用):

调用my_func T的类型 tmprv的类型
my_func(i) int int&
my_func(j) const int const int&
my_func(k) const int const int &

    注意:1.若实参是引用类型,则引用类型会被忽略掉,T不会被推导为引用类型。2.实参的const属性会成为类型模板参数T类型推导的组成部分,所以不用担心在my_func中能够修改原来有const属性的实参

template<typename T>
void my_func(const T& tmprv){}
int i = 18;
const int j = i;
const int& k=i; 

  如果tmprv多了个const

调用my_func T的类型 tmprv的类型
my_func(i) int const int&
my_func(j) int const int&
my_func(k) int const int&

    注意:1.若实参是引用类型,则引用类型会被忽略掉,T不会被推导为引用类型。2.如果模板函数my_func的形参tmprv里边出现了const,则T中的const属性会被剥夺

template<typename T>
void my_func(T* tmprv){}
int i = 18;
const int j = i;
const int& k=i; 
const int *pi=&i;
调用my_func T的类型 tmprv的类型
my_func(&i) int int*
my_func(pi) const int const int*

  结论:如果tmprv中没有const,则实参中的const就会被带到T类型中去。如果tmprv有const,则T类型中不会带const。

template<typename T>
void my_func(T&& tmprv){}
int i = 18;
const int j = i;
const int& k=i; 

  如果tmprv类型是个万能引用

调用my_func T的类型 tmprv的类型
my_func(i) int& int&
my_func(j) const int& const int&
my_func(k) const int& const int&
my_func(100) int int&&

  如果tmprv类型是个常规的传值方式传递

void testFunc(){}
template<typename T>
void my_func(T tmprv){}
int i = 18;
const int j = i;
const int& k=i; 
char mystr[]="I Love Myself!";
const char* const point = mystr;
const char c_mystr[]= "I Love China!";
调用my_func T的类型 tmprv的类型
my_func(i) int int
my_func(j) int int
my_func(k) int int
my_func(c_mystr) const char* const char *
my_func(point) const char* const char *
my_func(testFunc) void(*)() void(*)()

  注意:由于tmprv是新副本,所以,const属性不会传递进去。但是如果你传递是const char*或者const char[]数组,那这个const会被保留

void testFunc(){}
template<typename T>
void my_func(T& tmprv){}
const char c_mystr[]= "I Love China!";
调用my_func T的类型 tmprv的类型
my_func(c_mystr) const char[14] const char(&)[14]
my_func(testFunc) void(void) void(&)(void)

  从而可以获取数组长度。看下例:

template<typename T,unsigned L1>
void my_func(T(&tmprv)[L1])
{
   cout<<"数组的长度是"<<L1<<endl;
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容