C++11:利用模板简化重载右值引用参数的函数

C++11标准中引入了右值的概念,是个非常好的东东,使用得当可以大大减少对象间无谓的复制(关于右值,左值的概念请自行问度娘)。

左值引用版本和右值引用版本的函数

下面是matrix_cl类的两个重载的构造函数,这两个构造函数除了最后一个参数不同,其他的参数都完全一样,只有最后一个参数不同(分别为右值和左值引用)。
当调用该构造函数时,如果最后一个参数为右值引用的时候,会优先调用第一个构造函数,使用移动语义std:move()rv转为右值,将rv的内容赋值给this->v,这时调用的是std::vector的移动赋值操作符 vector&operator=(vector&&),这样,this->v不会重新分配内存,而是直接使用rv的内存数据。

// 右值引用版本
matrix_cl(size_t width, size_t height, uint8_t align,std::vector<E> &&rv):matrix_cl(width,height,align) 
{
	throw_if(rv.size()&&get_row_stride()*height!=rv.size()) // 参数合法性检查,请无视
	this->v=std::move(rv); // 移动语义 
	// 这里的=为移动赋值操作符std::vector& operator=(const vector&&)
};

// 左值引用版本
matrix_cl(size_t width, size_t height, uint8_t align,const std::vector<E> &lv):matrix_cl(width,height,align){
	throw_if(lv.size()&&get_row_stride()*height!=lv.size())
	this->v=lv;
	// 这里的=为复制赋值操作符 std::vector& operator=(const vector&)
};

注:上面代码中模板参数E为类模板参数,请忽视,下同。

如果最后一个参数不是右值引用,则会调用第二个函数(左值引用版本),这时this->v=lv;调用的是std::vector的复制赋值操作符 vector&operator=(vector&),这样,this->v会重新分配内存将lv的内容复制一份。

能不能更简化?

这样看起来一切都挺完美。。。但是,好像哪里不对。。。
如果按照上面的路子,对于复杂类型的参数对象,都要分别提供左值和右值引用两个版本,才能分别针对右值和右值进行处理。。。。上面的例子中构造函数只有3行,还好办,如果构造函数有30行甚至更多的代码,我们岂不是要把这些代码几乎原样复制两个版本?如果真是这样的话,这代码的就太臃肿了,可维护性也不好啊,能不能将两个函数合并为一个?
yes!we can

如果要把上面两个函数合并为一个就要用到模板编程了。

下面是合并后的代码。

template<typename _V=std::vector<E>
	,bool _RV=std::is_rvalue_reference<_V&&>::value // 模板常量参数,用于判断v是否为右值引用
	>
matrix_cl(size_t width, size_t height, uint8_t align,_V &&v):matrix_cl(width,height,align){
	throw_if(v.size()&&get_row_stride()*height!=v.size())
	this->v=_RV?std::move(v):v;
};

这里用到了#include <type_traits>中的[std::is_rvalue_reference][1]来判断参数v的引用类型,
然后在函数体内根据_RV的值来决定调用std::move将v转为右值引用,还是直接赋值.

更严谨的写法

其实更严谨的写法,还应该为模板参数_V加上类型限制,代码如下

template<typename _V
	,bool _RV=std::is_rvalue_reference<_V&&>::value // 模板常量参数,用于判断v是否为右值引用
	,typename _ENABLE=typename std::enable_if<std::is_base_of<std::vector<E>,typename std::decay<_V>::type>::value>::type
	// _ENABLE参数限制_V必须是std::vector<E>或其子类
	>
matrix_cl(size_t width, size_t height, uint8_t align,_V &&v):matrix_cl(width,height,align){
	throw_if(v.size()&&get_row_stride()*height!=v.size())
	this->v=_RV?std::move(v):v;
};

有了_ENABLE进行参数类型限制,在类中有多个类型的模板构造函数的情况,调用构造函数时就不会将别的类型的参数误传入,而产生编译错误。
这里用到的[std::enable_if][3],[std::is_base_of][2],[std::decay][4]都是定义在#include<type_traits>中的模板函数,详细说明请打开链接查看。
[1]:http://www.cplusplus.com/reference/type_traits/is_rvalue_reference/
[2]:http://www.cplusplus.com/reference/type_traits/is_base_of/
[3]:http://www.cplusplus.com/reference/type_traits/enable_if/
[4]:http://www.cplusplus.com/reference/type_traits/decay/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值