在std::promise范例中,使用了std::ref将future对象传递给引用参数类型的任务函数。
如果直接传入pr,将会出现编译错误:
error C2661: “std::tuple,std::promise>::tuple”: 没有重载函数接受 2 个参数
说明函数调用的参数类型不匹配。
查看thread的源代码,其构造函数依赖于一个rvalue-reference类型的variaic templates参数列表:
template::type, thread>::value>::type>explicit
thread(_Fn&& _Fx, _Args&&... _Ax){
// construct with _Fx(_Ax...)
_Launch(&_Thr,
_STD make_unique, decay_t<_Args>...> >(
_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...));
}
其中的“_Args&&... _Ax”也是C++11引入的新特性:Variadic templates,它允许函数可以接受任意个不同类型的参数,类似于C语言中的可变参数。在参考文档[4]中说,”However, thanks to variadic templates, programming new features using templates has become easier, clearer & more memory-efficient.“,为什么内存效率更高呢?参考[6]中解释说:参数列表所形成的一个parameter pack在编译期间被解包,C++利用编译期的处理实现了运行时效率优化。参考[5]中说:”Variadic templates are a trustworthy solution to implement delegates and tuples. And, instead of C-style ellipsis mechanism, variadic templates can offer a typesafer solution to replace them.“具体如何实现delegates和tuples,另行描述。
除了可变模板,另外两个相关的新技术是rvalue-reference和reference_wrapper,这两者和move语义是紧密相连的,如此节省了很多右值对象的复制构造开销。
std::ref(pr)返回的对象类型是一个reference_wrapper,而不是对pr的直接引用(T&,即std::promise&)。
换一个参考[7]中的例子:
上述代码的结果是0!为什么?因为bind方法通过传值方式传入参数,在被传递给绑定目标add方法之前,变量”result“已经被重新拷贝了。因为bind必须确保传入的参数是持续可用的。
解决方法很简单,使用reference_wrapper:
使用如下代码定义reference_wrapper对象:
reference_wrapper r=x;// or auto r = ref(x);
通过r对象的get函数(r.get()),r的作用与直接引用完全一样。
还可以用来创建引用数组,例如:
std::reference_wrapper在泛型代码中用处广泛,它存储的是对象的指针,有引用的全部功能,还实现了引用的拷贝(包括拷贝构造和拷贝赋值),可以在程序中存储引用而不是整个对象。
reference_wrapper和shared_ptr如何选择?两者都可以实现指针层面的复制和操作,但是前者不允许默认构造函数,在容器中也不能使用resize等方法。另外可能还有一些不同之处,但是基本上没有太大区别了。
参考资料:
[1] http://stackoverflow.com/questions/33240993/c-difference-between-stdreft-and-t
[2] http://stackoverflow.com/questions/26766939/difference-between-stdreference-wrapper-and-simple-pointer
[3] http://stackoverflow.com/questions/31013689/why-does-stdthread-take-function-to-run-by-rvalue
[4] http://softwareengineering.stackexchange.com/questions/273448/polymorphic-template-container-shared-ptr-vs-reference-wrapper
[5] http://www.cplusplus.com/articles/EhvU7k9E/
[6] Real-Time C++: Efficient Object-Oriented and Template Microcontroller Programming, 2015-12,Christopher Kormanyos
[7] https://oopscenities.net/2012/08/09/reference_wrapper/