【C/C++】【C++11】模板类型推导
查看类型推断结果
需要清楚编译器推断出来的模板参数以及普通参数类型是什么;
通过查看编译器类型推断的结果;掌握C++类型推断的规则;
借助boost库:利用boost库来把编译器推断的类型信息打印出来;官网:www.boost.org
模板类型推断
#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
template <typename T> //T是类型模板参数,T是由类型的
void func(const T& tmp)//tmp形参,形参是有类型的 tmp形参的类型和T模板参数的类型不一样
{
//T的类型不仅仅和调用者提供的实参有关系,还和tmp的类型有关;
cout << "--------------s-----------------" << endl;
using boost::typeindex::type_id_with_cvr;
cout << "T = " << type_id_with_cvr<T>().pretty_name() << endl; //显示T类型
cout << "tmp = " << type_id_with_cvr<decltype(tmp)>().pretty_name() << endl; //显示tmp类型
cout << "---------------e----------------" << endl;
}
int main()
{
func(100);
//T = int
//tmp = int const&
return 0;
}
指针或者引用类型
如果tmp类型是个指针或者引用,但不是个万能引用;
-
若实参是引用类型,则引用类型会被忽略掉,T不会被推导为引用类型;
-
实参为const类型,形参也是const;实参的const属性会成为类型模板参数T类型推导的
//函数模板的形参为 T& tmp #include <iostream> #include <boost/type_index.hpp> using namespace std; template <typename T> //T是类型模板参数,T是由类型的 void func(T& tmp)//tmp形参,形参是有类型的 tmp形参的类型和T模板参数的类型不一样 { //T的类型不仅仅和调用者提供的实参有关系,还和tmp的类型有关; cout << "--------------s-----------------" << endl; using boost::typeindex::type_id_with_cvr; cout << "T = " << type_id_with_cvr<T>().pretty_name() << endl; //显示T类型 cout << "tmp = " << type_id_with_cvr<decltype(tmp)>().pretty_name() << endl; //显示tmp类型 cout << "---------------e----------------" << endl; } int main() { int i = 19; const int j = i; const int& k = i; func(i); //T = int tmp = int & func(j); //T = const int tmp = const int & func(k); //T = const int tmp = const int & return 0; }
-
若实参为引用类型,则引用类型会被忽略掉,T不会被推导为引用类型;
-
对于有const属性的实参,在T中推导后,T中的const属性没有,因为模板函数func的形参tmp里面出现了const
#include <iostream> #include <boost/type_index.hpp> using namespace std; template <typename T> //T是类型模板参数,T是由类型的 void func(const T& tmp)//tmp形参,形参是有类型的 tmp形参的类型和T模板参数的类型不一样 { //T的类型不仅仅和调用者提供的实参有关系,还和tmp的类型有关; cout << "--------------s-----------------" << endl; using boost::typeindex::type_id_with_cvr; cout << "T = " << type_id_with_cvr<T>().pretty_name() << endl; //显示T类型 cout << "tmp = " << type_id_with_cvr<decltype(tmp)>().pretty_name() << endl; //显示tmp类型 cout << "---------------e----------------" << endl; } int main() { int i = 19; const int j = i; const int& k = i; func(i); //T = int tmp = const int & func(j); //T = int tmp = const int & func(k); //T = int tmp = const int & //若实参为引用类型,则引用类型会被忽略掉,T不会被推导为引用类型; //对于有const属性的实参,在T中推导后,T中的const属性没有,因为模板函数func的形参tmp里面出现了const return 0; }
-
指针
#include <iostream> #include <boost/type_index.hpp> using namespace std; template <typename T> //T是类型模板参数,T是由类型的 void func(T* tmp)//tmp形参,形参是有类型的 tmp形参的类型和T模板参数的类型不一样 { //T的类型不仅仅和调用者提供的实参有关系,还和tmp的类型有关; cout << "--------------s-----------------" << endl; using boost::typeindex::type_id_with_cvr; cout << "T = " << type_id_with_cvr<T>().pretty_name() << endl; //显示T类型 cout << "tmp = " << type_id_with_cvr<decltype(tmp)>().pretty_name() << endl; //显示tmp类型 cout << "---------------e----------------" << endl; } int main() { int i = 19; const int *j = &i; func(&i); //T = int, tmp = int * func(j); //T = const int, tmp = const int * //如果tmp中没有const,则实参中的const会被带到T类型中去,如果tmp中有const,则T类型中不会带const; return 0; }
万能引用
如果tmp类型是个万能引用:T&&;左值和右值都能接受;
#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
template <typename T> //T是类型模板参数,T是由类型的
void func(T&& tmp)//tmp形参,形参是有类型的 tmp形参的类型和T模板参数的类型不一样
{
//T的类型不仅仅和调用者提供的实参有关系,还和tmp的类型有关;
cout << "--------------s-----------------" << endl;
using boost::typeindex::type_id_with_cvr;
cout << "T = " << type_id_with_cvr<T>().pretty_name() << endl; //显示T类型
cout << "tmp = " << type_id_with_cvr<decltype(tmp)>().pretty_name() << endl; //显示tmp类型
cout << "---------------e----------------" << endl;
}
int main()
{
int i = 19;
const int j = i;
const int& k = i;
func(i); //i是左值,T = int &, tmp = int &
func(j); //j是左值,T = const int &, tmp = const int &
func(k); //k是左值,T = const int &, tmp = const int &
func(100); //100是右值,T = int, tmp = int &&
return 0;
}
传值方式
如果tmp是常规的传值方式;
#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
template <typename T> //T是类型模板参数,T是由类型的
void func(T tmp)//tmp形参,形参是有类型的 tmp形参的类型和T模板参数的类型不一样
{
//T的类型不仅仅和调用者提供的实参有关系,还和tmp的类型有关;
cout << "--------------s-----------------" << endl;
using boost::typeindex::type_id_with_cvr;
cout << "T = " << type_id_with_cvr<T>().pretty_name() << endl; //显示T类型
cout << "tmp = " << type_id_with_cvr<decltype(tmp)>().pretty_name() << endl; //显示tmp类型
cout << "---------------e----------------" << endl;
}
int main()
{
int i = 19;
const int j = i;
const int& k = i;
func(i); //T = int , tmp = int
func(j); //T = int , tmp = int const属性没有传递进去,因为对方是新副本
func(k); //T = int , tmp = int const属性没有传递进去,因为对方是新副本
func(100); //T = int , tmp = int
char str[] = "Hello world!";
const char* const point = str; //第一个const表示point指向的目标中的内容不能通过point来改变;
//第二个const表示point的指向不能改变;
func(point); //T = char const *, tmp = char const *;第一个const保留,第二个const丢了;
func(str);
//总结:传递的是const char*或者const char[]数组,则这个const会被保留
return 0;
}
数组做实参
数组名代表数组首地址;
值传递
#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
template <typename T> //T是类型模板参数,T是由类型的
void func(T tmp)//tmp形参,形参是有类型的 tmp形参的类型和T模板参数的类型不一样
{
//T的类型不仅仅和调用者提供的实参有关系,还和tmp的类型有关;
cout << "--------------s-----------------" << endl;
using boost::typeindex::type_id_with_cvr;
cout << "T = " << type_id_with_cvr<T>().pretty_name() << endl; //显示T类型
cout << "tmp = " << type_id_with_cvr<decltype(tmp)>().pretty_name() << endl; //显示tmp类型
cout << "---------------e----------------" << endl;
}
int main()
{
const char str[] = "Hello world";
func(str); //T = char const *, tmp = char const *
return 0;
}
引用传递
#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
template <typename T> //T是类型模板参数,T是由类型的
void func(T& tmp)//tmp形参,形参是有类型的 tmp形参的类型和T模板参数的类型不一样
{
//T的类型不仅仅和调用者提供的实参有关系,还和tmp的类型有关;
cout << "--------------s-----------------" << endl;
using boost::typeindex::type_id_with_cvr;
cout << "T = " << type_id_with_cvr<T>().pretty_name() << endl; //显示T类型
cout << "tmp = " << type_id_with_cvr<decltype(tmp)>().pretty_name() << endl; //显示tmp类型
cout << "---------------e----------------" << endl;
}
int main()
{
const char str[] = "Hello world";
func(str); //T = char const [12], tmp = char const (&)[12]
return 0;
}
输出数组大小
#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
template <typename T, unsigned L> //T是类型模板参数,T是由类型的
void func(T (&tmp) [L])//tmp形参,形参是有类型的 tmp形参的类型和T模板参数的类型不一样
{
//T的类型不仅仅和调用者提供的实参有关系,还和tmp的类型有关;
cout << L << endl;
cout << "--------------s-----------------" << endl;
using boost::typeindex::type_id_with_cvr;
cout << "T = " << type_id_with_cvr<T>().pretty_name() << endl; //显示T类型
cout << "tmp = " << type_id_with_cvr<decltype(tmp)>().pretty_name() << endl; //显示tmp类型
cout << "---------------e----------------" << endl;
}
int main()
{
const char str[] = "Hello world";
func(str);
return 0;
}
函数名做实参
函数名相当于函数首地址,可以赋值给一个函数指针
传值
#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
void test()
{
};
template <typename T> //T是类型模板参数,T是由类型的
void func(T tmp)//tmp形参,形参是有类型的 tmp形参的类型和T模板参数的类型不一样
{
//T的类型不仅仅和调用者提供的实参有关系,还和tmp的类型有关;
cout << "--------------s-----------------" << endl;
using boost::typeindex::type_id_with_cvr;
cout << "T = " << type_id_with_cvr<T>().pretty_name() << endl; //显示T类型
cout << "tmp = " << type_id_with_cvr<decltype(tmp)>().pretty_name() << endl; //显示tmp类型
cout << "---------------e----------------" << endl;
}
int main()
{
func(test); //T = void (__cdecl*)(void) tmp = void (__cdecl*)(void) 传值推断成函数指针
return 0;
}
传引用
#include <iostream>
#include <boost/type_index.hpp>
using namespace std;
void test()
{
};
template <typename T> //T是类型模板参数,T是由类型的
void func(T &tmp)//tmp形参,形参是有类型的 tmp形参的类型和T模板参数的类型不一样
{
//T的类型不仅仅和调用者提供的实参有关系,还和tmp的类型有关;
cout << "--------------s-----------------" << endl;
using boost::typeindex::type_id_with_cvr;
cout << "T = " << type_id_with_cvr<T>().pretty_name() << endl; //显示T类型
cout << "tmp = " << type_id_with_cvr<decltype(tmp)>().pretty_name() << endl; //显示tmp类型
cout << "---------------e----------------" << endl;
}
int main()
{
func(test); //T = void (__cdecl)(void)
//tmp = void (__cdecl&)(void)函数引用;
return 0;
}
总结
- 推断中,引用类型的实参的 引用类型等于不存在;
- 万能引用,实参为左值和右值,推断 结果不同;
- 按值传递的实参,传递给形参时const属性不起作用,则传递过去指针则另当别论;
- 数组或者函数类型在类型推断过程中被看作是指针,除非函数模板的形参是引用;
知识的价值不在于占有,而在于使用