前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++11:利用模板简化重载右值引用参数的函数

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

作者头像
10km
发布2019-05-25 22:42:24
8430
发布2019-05-25 22:42:24
举报
文章被收录于专栏:10km的专栏

版权声明:本文为博主原创文章,转载请注明源地址。 https://cloud.tencent.com/developer/article/1433789

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

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

下面是matrix_cl类的两个重载的构造函数,这两个构造函数除了最后一个参数不同,其他的参数都完全一样,只有最后一个参数不同(分别为右值和左值引用)。

当调用该构造函数时,如果最后一个参数为右值引用的时候,会优先调用第一个构造函数,使用移动语义std:move()rv转为右值,将rv的内容赋值给this->v,这时调用的是std::vector的移动赋值操作符 vector&operator=(vector&&),这样,this->v不会重新分配内存,而是直接使用rv的内存数据。

代码语言:javascript
复制
// 右值引用版本
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

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

下面是合并后的代码。

代码语言:javascript
复制
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来判断参数v的引用类型,

然后在函数体内根据_RV的值来决定调用std::move将v转为右值引用,还是直接赋值.

更严谨的写法

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

代码语言:javascript
复制
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,std::is_base_of,std::decay都是定义在#include<type_traits>中的模板函数,详细说明请打开链接查看。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016年03月08日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 左值引用版本和右值引用版本的函数
  • 能不能更简化?
  • 更严谨的写法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档