【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属性不起作用,则传递过去指针则另当别论;
  • 数组或者函数类型在类型推断过程中被看作是指针,除非函数模板的形参是引用;
posted @ 2020-08-06 10:57  NaughtyCoder  阅读(460)  评论(0)    收藏  举报