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

  • Post author:
  • Post category:其他


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

来判断参数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

,

std::is_base_of

,

std::decay

都是定义在

#include<type_traits>

中的模板函数,详细说明请打开链接查看。



版权声明:本文为10km原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。