在某些情况下,如在子线程运行一个函数,即使该函数的参数了引用类型,实际上传递时还是要拷贝对象。如果这时希望实际传引用,可以使用 ref 库中定义的引用类型包装器 reference_wrapper。ref 也被加入到标准库了。
#include <boost/ref.hpp>
using namespace boost;
int main()
{
int x = 10;
reference_wrapper<int> rw(x);//将x的引用包装为一个对象
qDebug()<<(x == rw);//true 隐式将reference_wrapper<int>类型转成int类型
(int &)rw = 100;//显示将rw转成int&类型
qDebug()<<(x == 100);//true
qDebug()<<rw.get();//get()获取储存的引用
qDebug()<<*rw.get_pointer();//get_pointer()获取储存的指针
reference_wrapper<int> rw2(rw);
assert(rw2.get() == 100);//true
*rw.get_pointer() = 200;
qDebug()<<rw.get();//200
}
工厂函数
reference_wrapper 的名字过长,因而 ref 库提供了两个便捷的工厂函数 ref()和 cref(),可以通过参数类型推导很容易地构造 reference_wrapper 对象。
这两个函数的声明如下:
reference_wrapper <T> ref(T& t)
reference_wrapper <T const> cref (T const& t)
double x = 2.71828;
auto rw = cref(x);
std::cout << typeid(rw).name() << std::endl;
std::string str;
auto rws = boost::ref(str);
std::cout << typeid(rws).name() << std::endl;
boost::cref(str);
std::cout << std::sqrt(ref(x)) << std::endl; //计算平方根
is_reference_wrapper 判断是否被包装
#include <boost/ref.hpp>
using namespace boost;
int main()
{
std::vector<int> v(10, 2) ;
auto rw = boost::cref(v);
assert(is_reference_wrapper<decltype(rw)>::value);
assert(!is_reference_wrapper<decltype(v)>::value);
}
unwrap_reference 获取真实类型,无论是否被包装
int main()
{
std::string str;
auto rws = boost::ref(str);
std::cout << typeid(unwrap_reference<decltype(rws)>::type).name() << std::endl;
std::cout << typeid(unwrap_reference<decltype(str)>::type).name() << std::endl;
}
unwrap_ref 解包装,返回被包装对象的引用
int main()
{
QList<int> list;
auto rw = boost::ref(list);
QList<int> & listRef = unwrap_ref(rw);
listRef.append(120);
unwrap_ref(rw).append(130);
qDebug()<<list;//QList(120, 130)
}
与标准库 ref 的区别
最大的区别是标准库的ref可以调用函数对象的操作符。
#include <boost/ref.hpp>
using namespace boost;
struct square
{
typedef void result_type;
result_type operator()(int &x)
{
x = x * x;
}
};
int main()
{
square sq;
int x = 5;
std::ref(sq)(x); //ok
// boost::ref(sq)(x); //error
std::cout << x << std::endl;
std::vector<int> v = {1,2,3,4,5};
for_each(v.begin(), v.end(), sq); //ok
// for_each(v.begin(), v.end(), std::ref(sq)); //ok
// for_each(v.begin(), v.end(), boost::ref(sq)); //error
qDebug()<<v;
}
所以尽量用标准库的。