(C++模板编程):完美转发范例

目录

在构造函数模板中使用完美转发范例

使用模板方式 + 完美转发

在可变参数模板中使用完美转发范例

常规的在可变参模板使用完美转发

将目标函数中的返回值通过转发函数返回给调用者函数

完美转发失败的情形一例

在构造函数模板中使用完美转发范例

class Human
{
public:
	//构造函数
	Human(const string& tmpname) :m_sname(tmpname)
	{
		cout << "Human(const string &tmpname)执行" << endl;
	}
private:
	string m_sname;
};
  • 调用
string sname = "ZhangSan";
Human myhuman1(sname);
Human myhuman2(string("LiSi")); //"LiSi"是const char[5]类型,而string("LiSi")是string类型。临时对象时右值。
  • 输出

  • 加入右值引用构造函数
class Human
{
public:
	//构造函数
	Human(const string& tmpname) :m_sname(tmpname)
	{
		cout << "Human(const string &tmpname)执行" << endl;
	}
Human(string&& tmpname) :m_sname(tmpname)  //tmpname本身是左值,传给m_sname为左值
	{
		cout << "Human(string&& tmpname)执行" << endl;
	}

private:
	string m_sname;
};
  • 调用
string sname = "ZhangSan";
Human myhuman1(sname);
Human myhuman2(string("LiSi")); //"LiSi"是const char[5]类型,而string("LiSi")是string类型。临时对象时右值。
  • 输出

  • 对于临时对象,如果有对应的右值引用的构造函数,优先使用右值引用类型。

案例:将构造初始化改成m_sname(std::move(tmpname)) ,传给m_sname为右值

class Human
{
public:
	//构造函数
	Human(const string& tmpname) :m_sname(tmpname)
	{
		cout << "Human(const string &tmpname)执行" << endl;
	}
Human(string&& tmpname) :m_sname(std::move(tmpname)) 
	{
		cout << "Human(string&& tmpname)执行" << endl;
	}

private:
	string m_sname;
};
  • Human(string&& tmpname) :m_sname(std::move(tmpname))
    • move并不具备移动能力,把一个左值转换成一个右值。调用string的移动构造函数,将tmpname的值移动到m_sname,移动后tmpname为空。

使用模板方式 + 完美转发

class Human
{
public:
	//构造函数模板
template<typename T>
    Human(T&& tmpname) : m_sname(std::forward<T>(tmpname))
    {
        cout << "Human(T&& tmpname)执行" << endl;
    }

private:
	string m_sname;
};
  • 调用
string sname = "ZhangSan";
Human myhuman1(sname);
Human myhuman2(string("LiSi")); //"LiSi"是const char[5]类型,而string("LiSi")是string类型。临时对象时右值。
  • 输出

案例:构造函数模板对拷贝构造函数造成影响,匹配混乱

class Human
{
public:
	//构造函数模板
template<typename T>
    Human(T&& tmpname) : m_sname(std::forward<T>(tmpname))
    {
        cout << "Human(T&& tmpname)执行" << endl;
    }
    //拷贝构造函数
Human(const Human& th) : m_sname(th.m_sname)
{
	cout << "Human(const Human& th)拷贝构造函数执行" << endl;
}


private:
	string m_sname;
};
  • 调用
string sname = "ZhangSan";
Human myhuman1(sname);

Human myhuman3(myhuman1); //实际编译器去调用了构造函数模板,而不是调用了拷贝构造函数。 
  • 构造函数模板对普通的拷贝构造函数造成影响

案例:增加移动构造函数的情形

class Human
{
public:
	//构造函数模板
template<typename T>
    Human(T&& tmpname) : m_sname(std::forward<T>(tmpname))
    {
        cout << "Human(T&& tmpname)执行" << endl;
    }
    //拷贝构造函数
Human(const Human& th) : m_sname(th.m_sname)
{
	cout << "Human(const Human& th)拷贝构造函数执行" << endl;
}

//移动构造函数
Human(Human&& th) : m_sname(std::move(th.m_sname))
{
	cout << "Human(Human&& th)移动构造函数执行" << endl;
}


private:
	string m_sname;
};
  • 调用
string sname = "ZhangSan";
Human myhuman1(sname);
Human myhuman2(string("LiSi"));

Human myhuman4(std::move(myhuman1));

const Human myhuman5(string("WangWu"));  //有const修饰,优先匹配拷贝构造函数
Human myhuman6(myhuman5);
  • 输出

在可变参数模板中使用完美转发范例

常规的在可变参模板使用完美转发

int funcLast(int v1, int& v2) //目标函数
{
	++v2; //改变v2的值,让其自增1
	cout << v1 + v2 << endl;
	return v1 + v2;
}

template <typename F, typename...T>
void funcMiddle_Temp(F f, T&&... t)
{
	return f(std::forward<T>(t)...);
}
  • 调用
int j = 70;
funcMiddle_Temp(_nmsp2::funcLast, 20, j);  //91
cout << "j = " << j << endl;   //71

将目标函数中的返回值通过转发函数返回给调用者函数

  • 用到的技术:auto结合decltype构成返回类型后置语法。
template <typename F, typename...T>
//auto funcMiddle_Temp(F f, T&&... t)->decltype(  f(std::forward<T>(t)...)   )
//后置这种方式可能出现引用丢失的问题,建议使用decltype(auto)
decltype(auto) funcMiddle_Temp(F f, T&&... t)
{
	return f(std::forward<T>(t)...);
}

int funcLast(int v1, int& v2) //目标函数
{
	++v2; //改变v2的值,让其自增1
	cout << v1 + v2 << endl;
	return v1 + v2;
}

  • 调用
int j = 70;
int k = funcMiddle_Temp(funcLast, 20, j);
cout << "j = " << j << endl;    //71
cout << "k = " << k << endl;   //91

完美转发失败的情形一例

  • 使用NULL或者0作为空指针进行参数传递时导致完美转发失败的情况。

//目标函数
void funcLast4(char* p)
{
	//if (p != NULL)
	if (p != nullptr)
	{
		strncpy(p, "abc",3);
	}
}

//转发函数
template <typename F, typename...T>
void funcMiddle_Temp(F f, T&&... t)
{
	f(std::forward<T>(t)...);
}
  • 调用
char* p = new char[100];
memset(p, 0, 100);
funcLast4(NULL);  //成功
funcMiddle_Temp(funcLast4, NULL);  //报错
  • 报错

  • C++11引入nullptr(空指针)
char* p = new char[100];
memset(p, 0, 100);
funcMiddle_Temp(funcLast4, nullptr);
  • 使用nullptr可正常调用。

【注】错误处理

  • 方法:文件最前面加入
#pragma warning(disable : 4996) 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值