c++函数模板参数推断

c++模板类型推断分为类模板类型推断和函数模板类型推断,这里主要讨论的是c++函数模板推断.

函数模板类型推断情况分为三种:

情况1:
template<typename T>
void func(T t)
{
	//....
}

此种情况最为简单,对于传递给函数模板的实参val,假设其类型为ParaType,若ParaType具有引用属性,则去掉引用属性,若具有const属性也去掉,最终得到的类型即为T的类型:

int i = 999;
func(i);		//实参i既无引用属性,也无const属性,T类型为int

const int ci = 250;
func(ci);		//实参ci有const属性,去掉,T类型为int

const int &cref = 520;
func(cref);		//去掉实参cref引用属性和const属性,T类型为int
情况2:
template<typename T>
void func(T &t)
{
	//...
}

这种情况下,对于传递给函数模板的实参val,类型为ParaType,若ParaType具有引用属性,则去掉引用属性,若具有const属性则保留。

int i = 999;
func(i);		//实参i既无引用属性,也无const属性,T类型为int

const int ci = 250;
func(ci);		//实参ci有const属性,T类型为const int

const int &cref = 520;
func(cref);		//去掉实参cref引用属性,T类型为const int

const int &&crref = 6666;
func(crref);		//去掉实参crref引用属性,T类型为const int
情况3:
template<typename T>
void func(T &&t)
{
	//...
}

这种情况即为所谓的万能引用,实参类型可以为任意类型(左值、右值、左值引用、右值引用,虽然将模板函数声明为const T&也可以接收任意类型,但是存在不能修改实参的限制)。

对于传递给此函数模板的实参:

  1. 当实参类型为左值 ** (注意左值、左值引用、右值引用均为左值) ** 时,T的类型会被推断为type&;当实参类型为右值时,T的类型会被推断为type。那type什么是类型呢?type即上述情况二中推导规则。
举例:
std::string s("fuck");
func(s);		//s为左值,type为std::stirng , T被推断为std::string &

const std::string &lref = s;
func(lref);		//lref为左值,type为const std::string T被推导为const std::string &

const std::string &&rref = std::string("fuck c++");
func(rref);		//同上
  1. 当实参类型为右值时,T的类型被推断为实参相应类型。
举例:
func(std::string("hello c++");		//T被推断为std::string

std::string s("give up c++");
func(std::move(s));		//T被推断为std::string

func(static_cast<std::string &&>(s));		//T被推断为 std::string

到此为止T的类型全部已知,直接将推断类型带入到函数模板即可得到实例化函数,例如:

//情况一
func(int t)		//T为int
{
	//...
}

//情况二
func(const int &t)		//T为const int
{
	//...
}

//情况三,实参为左值时
func(const std::string& &&t)		//T为const std::string &
{
	//...
}

//情况三,实参为右值时
func(std::string &&t)		/T为std::string
{
	//...
}

在情况三中,当实参为左值时其实例化结果有点奇怪,编译器并不允许程序员直接这样写,通过引用折叠,最终版本为:

//可以看到,当实参为左值类型(左值、左值引用、右值引用)时,最终t都会绑定到一个左值对象或右值对象上
func(const std::string &t)	
{
	//....
}

猜你喜欢

转载自blog.csdn.net/qq_39815320/article/details/104971118