目录
类型推断规则
万能引用类型
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; }