目录
查看类型推断结果
- 如何查看类型推断结果
- 当前要解决的问题:如何查看类型推断结果——指编译器给我们进行类型推断的结果
- 通过“查看编译器类型推断结果”的手段来学习并掌握C++类型推断的规则。
- 如何查看编译器帮助我们进行类型推断的结果。依赖Boost库——利用这个库把编译器推断出来的类型信息打印出来。
- boost库引入项目
boost类型查看应用
#include <boost/type_index.hpp> using namespace std; //函数模板 template <typename T> void myfunc(const 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(100);
- 输出
- myfunc中T的类型不仅仅取决于实参100,还取决于tmprv的类型(const T&)有关。
- 函数模板的形参(tmprv)是如下类型时编译器推断出的 类型模板参数的类型(T),以及最终的函数形参类型(tmprv)
引用类型
T& tmprv类型推断
//函数模板 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 &。实际结果:T =int,tmprv = int & ,猜测正确 myfunc(j); //因为j类型中有一个const,猜不出来。实际结果:T=int const tmprv=int const & myfunc(k); //猜不出来。实际结果:T=int const tmprv=int const &
- 输出
- T的类型由实参类型(正推T)和tmpr类型(反推T)共同决定。
示例
void mf(int& tmprv) { tmprv = 12; } int main() { int ii = 1; int& jj = ii; mf(jj); cout << ii << endl; //输出 12 return 0; }
- 改成模板类型
template <typename T> void mf(T& tmprv) { tmprv = 12; 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 main() { int ii = 1; int& jj = ii; mf(jj); cout << ii << endl; //输出 12 return 0; }
- 输出
T tmprv类型推断
template <typename T> void mf(T tmprv) { tmprv = 12; 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 main() { int ii = 1; int& jj = ii; mf(jj); cout << ii << endl; //输出 1 return 0; }
- 输出
- jj是 int& 类型,T推断成int 类型,实参是引用类型,那么引用部分会被忽略,T不会被推导为引用类型。此时tmprv前面没有加&,就无法达到通过函数更改 ii 值的意图。
T&tmprv类型推断<补充>
当向引用类型的形参tmprv传入const类型实参时了,那么形参tmprv会成为const引用(形参tmprv原来是个引用)
- 实参的const属性会成为类型模板参数T类型推导的组成部分,所以不用担心在形参中能够修改原来const属性的实参。
//函数模板 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 = 15; }
- 调用
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 &
- 如果添加了tmprv = 15; 想改变原来的值,则报如下错误。
- 总结:实参原来本身带有const属性(即该值不应该被改变),传给带有&的形参,依然保留这种属性,不能因为形参有&就可以改变原来的值,因此不用担心实参值被修改。
const T&tmprv类型推断
template <typename T> void myfunc(const 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 const & myfunc(j); //实际结果:T=int tmprv=int const & myfunc(k); //实际结果:T=int tmprv=int const &
- 输出
- 若实参是引用类型,那么引用部分会被忽略,T不会被推导为引用类型。
- T中的const没有了,因为函数模板的形参tmprv里出现const(T的类型不仅仅取决于实参类型,还取决于tmprv的类型(const T&))。
- 只要实参带const,形参tmprv中终究还是会带着const。
编程技巧总结
- a)形参中引用有两个作用:1是可以通过对形参的修改来修改实参。2是传递引用比传值效率高。
- 一般来说,函数模板中的形参建议优先考虑“T &tmprv”这样的形态,
- 这样的形态就不怕实参中的引用被忽略掉而导致开发者想通过对形参的修改达到修改实参的本意无法达成,如前面的void mf(T tmprv)案例。
- b)如何既想享受形参为引用带来的效率上的提高,又不希望通过形参来修改实参,则函数模板中的形参建议考虑“const T &tmprv”这样的形态。
指针类型
T* tmprv类型推断
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; const int* pi = &i; myfunc(&i); myfunc(pi);
- 输出
const T* tmprv类型推断
template <typename T> void myfunc(const 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; const int* pi = &i; myfunc(&i); myfunc(pi);
- 输出
- tmprv中如果没有const,则实参中的const会被带到类型T中去。如果tmprv中有const,则T类型中不会带const。
- 这个结论对于myfunc中形参为T& tmprv或者const T& tmprv也适用。
- 要点:T& tmprv、const T& tmprv、* tmprv和const T* tmprv,T的类型由传入的实参类型及tmprv类型共同决定。