(C++模板编程):常用类型推断规则、auto类型常规推断

目录

类型推断规则

万能引用类型

传值方式

传值方式的引申——std::ref与std::cref

数组做实参

提取字符串长度小技巧

函数名做实参

初始化列表做实参

总结

auto类型常规推断:用于变量的自动类型推断

传值方式(非指针,非引用)

指针或者引用类型但不是万能引用

万能引用类型

类型推断规则

万能引用类型

template <typename T>
void myfunc(T&& tmprv) 
{
	cout << "--------------------------------begin----------------" << endl;
	using boost::typeindex::type_id_with_cvr;
	cout << "T=" << type_id_with_cvr<T>().pretty_name() << endl; //显示T的类型
	cout << "tmprv=" << type_id_with_cvr<decltype(tmprv)>().pretty_name() << endl; //显示tmprv的类型
	cout << "--------------------------------end------------------" << endl;	
}
  • 调用
int i = 18; //i的类型是int
const int j = i; //j的类型是const int
const int& k = i; //k的类型是const int &
myfunc(i); //T = int & ,tmprv = int &
myfunc(j); //T = int const & ,tmprv = int const &
myfunc(k); //T = int const & ,tmprv = int const &

myfunc(100);//T = int ,tmprv = int &&
  • 输出

传值方式

template <typename T>
void myfunc(T tmprv) 
{
	cout << "--------------------------------begin----------------" << endl;
	using boost::typeindex::type_id_with_cvr;
	cout << "T=" << type_id_with_cvr<T>().pretty_name() << endl; //显示T的类型
	cout << "tmprv=" << type_id_with_cvr<decltype(tmprv)>().pretty_name() << endl; //显示tmprv的类型
	cout << "--------------------------------end------------------" << endl;	
}
  • 调用
int i = 18; //i的类型是int
const int j = i; //j的类型是const int
const int& k = i; //k的类型是const int &
myfunc(i); //T = int  ,tmprv = int 
myfunc(j); //T = int  ,tmprv = int 
myfunc(k); //T = int  ,tmprv = int 

int& m = i;	
myfunc(m);
myfunc<int &>(m);  //手动指定类型

  • 输出

  • 结论:若实参是引用类型,则引用部分会被忽略,T不会被推导为引用类型。除非手工指定为引用类型(不建议这样写代码)。
  • 若实参是const类型,则const部分会被忽略,T不会推导为const类型(毕竟产生的是新副本);

【注意】传入指针类型

char mystr[] = "I Love China";
const char* const p = mystr; //第一个const表示p指向的目标中的内容不能通过p改变
	                         //第二个const表示p指向一个内容后,p不可以再指向其他内容(p不可以指向不同目标)。
myfunc(p);  //T = char const *,tmprv=char const * ,传递给myfunc后,第二个const没有了,第一个const是保留的。
	        //这表示进入到myfunc函数模板内部后,tmprv指向的内容不能通过tmprv改变,但是tmprv可以指向其他内存地址。
	        //也就是说tmprv(p)的常量性被忽略了,而tmprv(p)所指向的内容的常量性会被保留。 
  • 输出

  • 如果传递的是const char *或者const char[],这个const会被保留。

传值方式的引申——std::ref与std::cref

  • 函数模板定义中使用传值方式时,可以通过std::ref和std::cref来以引用方式传递参数
  • std::ref和std::cref象对象包装器,编译器通过创建一个 class std::reference_wrapper<T>类型的对象
template <typename T>
void myfunc(T tmprv) 
{
	cout << "--------------------------------begin----------------" << endl;
	using boost::typeindex::type_id_with_cvr;
	cout << "T=" << type_id_with_cvr<T>().pretty_name() << endl; //显示T的类型
	cout << "tmprv=" << type_id_with_cvr<decltype(tmprv)>().pretty_name() << endl; //显示tmprv的类型
	cout << "--------------------------------end------------------" << endl;	
	//tmprv = 1200;  tmprv是class std::reference_wrapper<int>类型,不能直接改
	int& tmpvaluec = tmprv;
	tmpvaluec = 1200;
}
  • 调用
int m = 180;
myfunc(std::ref(m)); //T=class std::reference_wrapper<int> ,tmprv=class std::reference_wrapper<int>
cout << "m=" << m << endl;
  • 输出

数组做实参

template <typename T>
void myfunc(T tmprv) 
{
	cout << "--------------------------------begin----------------" << endl;
	using boost::typeindex::type_id_with_cvr;
	cout << "T=" << type_id_with_cvr<T>().pretty_name() << endl; //显示T的类型
	cout << "tmprv=" << type_id_with_cvr<decltype(tmprv)>().pretty_name() << endl; //显示tmprv的类型
	cout << "--------------------------------end------------------" << endl;	
}
  • 调用
char mystr[] = "I Love China";
const char* const p = mystr; 
	                      
myfunc(p);  //T = char const *,tmprv=char const * 
  • 输出

【对比】将形参改成 T&

template <typename T>
void myfunc(T& tmprv) 
{
	cout << "--------------------------------begin----------------" << endl;
	using boost::typeindex::type_id_with_cvr;
	cout << "T=" << type_id_with_cvr<T>().pretty_name() << endl; //显示T的类型
	cout << "tmprv=" << type_id_with_cvr<decltype(tmprv)>().pretty_name() << endl; //显示tmprv的类型
	cout << "--------------------------------end------------------" << endl;	
}
  • 调用
const char mystr[] = "I Love China!";
myfunc(mystr); //T=char const [14],tmprv=char const (&)[14]--(&)代表数组的一个引用。
  • 输出

提取字符串长度小技巧

template <typename T,unsigned L1>   //L1就是数组长度
void myfunc(T (&tmprv)[L1] )
{
    cout << "--------------------------------begin----------------" << endl;
	using boost::typeindex::type_id_with_cvr;
	cout << "T=" << type_id_with_cvr<T>().pretty_name() << endl; //显示T的类型
	cout << "tmprv=" << type_id_with_cvr<decltype(tmprv)>().pretty_name() << endl; //显示tmprv的类型
	cout << "--------------------------------end------------------" << endl;	
	cout << L1 << endl;
}
  • 调用
const char mystr[] = "I Love China!";
myfunc(mystr);  //输出14
  • 输出

函数名做实参

template <typename T>
void myfunc(T tmprv) 
{
	cout << "--------------------------------begin----------------" << endl;
	using boost::typeindex::type_id_with_cvr;
	cout << "T=" << type_id_with_cvr<T>().pretty_name() << endl; //显示T的类型
	cout << "tmprv=" << type_id_with_cvr<decltype(tmprv)>().pretty_name() << endl; //显示tmprv的类型
	cout << "--------------------------------end------------------" << endl;	
}

void testFunc() {}
  • 调用
myfunc(testFunc);
  • 输出

  • 【对比】改成引用传递
template <typename T>
void myfunc(T& tmprv) 
{
	cout << "--------------------------------begin----------------" << endl;
	using boost::typeindex::type_id_with_cvr;
	cout << "T=" << type_id_with_cvr<T>().pretty_name() << endl; //显示T的类型
	cout << "tmprv=" << type_id_with_cvr<decltype(tmprv)>().pretty_name() << endl; //显示tmprv的类型
	cout << "--------------------------------end------------------" << endl;	
}

void testFunc() {}
  • 调用
myfunc(testFunc);  // T=void __cdecl(void),tmprv=void (__cdecl&)(void)——tmprv是一个函数引用类型:void(&)(void)
  • 输出

初始化列表做实参

template <typename T>
void myfunc(std::initializer_list<T>  tmprv)
{
	cout << "--------------------------------begin----------------" << endl;
	using boost::typeindex::type_id_with_cvr;
	cout << "T=" << type_id_with_cvr<T>().pretty_name() << endl; //显示T的类型
	cout << "tmprv=" << type_id_with_cvr<decltype(tmprv)>().pretty_name() << endl; //显示tmprv的类型
	cout << "--------------------------------end------------------" << endl;	
}
  • 调用
myfunc({1,2,3}); //T=int,tmprv=class std::initializer_list<int>
  • 输出

总结

  • a推断中,引用类型实参的引用类型等于不存在。
  • b) 万能引用,实参为左值或者右值,推断的结果不同。
  • c) 按值传递的实参,传递给形参时const属性不起作用,但传递进去指针则另当别论。
  • d) 数组或者函数类型在类型推断中会被看做是指针,除非函数模板的形参是个引用。
  • e) 初始化列表不能直接推断成initializer_list类型,必须在函数模板的形参中明确指出使用initializer_list类型。

auto类型常规推断:用于变量的自动类型推断

  • 声明变量的时候根据变量初始化的类型自动为此变量选择匹配的类型,不需要程序员显式的指定类型。
  • auto的特点:
    • a)auto的自动类型推断发生在编译期间
    • b)auto定义变量必须立即初始化,这样编译器才能推断出他的实际类型。
      • 编译的时候才能确定auto类型以及整个变量的类型。
      • 在编译期间就可以用真正的类型替换掉auto这个类型占位符了
    • c)auto的使用比较灵活,可以和指针、引用、const等限定符结合使用
  • auto推断出来后会代表一个具体类型,auto相当于函数模板类型推断中的参数T
auto x = 27; //auto有一个类型,x也有 一个类型。
	         //x =int ,auto = int。

传值方式(非指针,非引用)

  • auto后面直接接变量名,这就叫传值方式。
  • 总结传值方式对auto类型:会抛弃引用,const等限定符
auto x = 27; //估计x = int,auto =int
const auto x2 = x; //估计x2 = const int,auto =int
const auto& xy = x; //这个auto并不是传值方式,估计xy = const int &,auto = int
auto xy2 = xy; //估计:xy2 = int,auto =int;。
//验证
using boost::typeindex::type_id_with_cvr;	
cout << "xy2=" << type_id_with_cvr<decltype(xy2)>().pretty_name() << endl;

指针或者引用类型但不是万能引用

  • auto后面接一个&这就叫引用类型。
  • 传指针或者引用方式针对auto类型:不会抛弃const限定符,但是会抛弃引用

验证:const auto& xy = x; 

  • 借用函数模板进行推断:const auto& xy看成形参, x看成实参
  • 把auto 换成 T , xy 换成tmpvr
template <typename T>
void tf(const T& tmprv) //这里把auto替换成T,xy就相当于这里的tmprv
{
	cout << "--------------------------------begin----------------" << endl;
	using boost::typeindex::type_id_with_cvr;
	cout << "T=" << type_id_with_cvr<T>().pretty_name() << endl; //显示T的类型
	cout << "tmprv=" << type_id_with_cvr<decltype(tmprv)>().pretty_name() << endl; //显示tmprv的类型
	cout << "--------------------------------end------------------" << endl;
}
  • 调用
tf(x); //实参中给的是x;  T=int,tmprv=int const &
  • 输出

示例

auto x = 27; //估计x = int,auto =int
const auto x2 = x; //估计x2 = const int,auto =int
const auto& xy = x; //这个auto并不是传值方式,估计xy = const int &,auto = int
auto xy2 = xy; //估计:xy2 = int,auto =int;。

auto& xy3 = xy; //估计 xy3 = const int &,auto = const int。针对auto类型:引用会被丢弃,const属性会被保留。
auto y = new auto(100); //估计:y = int *,auto = int *,auto可以用于new。
const auto* xp = &x; //估计:xp = cont int *,auto = int
auto* xp2 = &x; //估计:xp2 = int *,auto = int
auto xp3 = &x; //估计:xp3 = int *,auto = int * ,xp3不声明为指针,也能推导出指针类型。

//验证
using boost::typeindex::type_id_with_cvr;	
cout << "xp3 =" << type_id_with_cvr<decltype(xp3 )>().pretty_name() << endl;

万能引用类型

  • 与函数模板类型推断时万能引用的情形完全相同。
auto&& wnyy0 = 222; //估计:万能引用,222是右值,auto = int,wnyy0 = int &&(右值引用类型)

auto x = 27; //估计x = int,auto =int
const auto x2 = x; //估计x2 = const int,auto =int
auto&& wnyy1 = x;   //估计:万能引用,x是左值,所以:auto  = int &,wnyy1 = int &。

auto&& wnyy2 = x2;  //编译器推断:auto = int const &,wnyy2 = int const &。
//tf(x2);
  • auto&& wnyy2 = x2; 用模板验证
template <typename T>
void tf(T&& tmprv)
{
	cout << "--------------------------------begin----------------" << endl;
	using boost::typeindex::type_id_with_cvr;
	cout << "T=" << type_id_with_cvr<T>().pretty_name() << endl; //显示T的类型
	cout << "tmprv=" << type_id_with_cvr<decltype(tmprv)>().pretty_name() << endl; //显示tmprv的类型
	cout << "--------------------------------end------------------" << endl;
}

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值