一、ref簡介html
reference_wrapper包含在ref庫中,它是引用包裝器類型,即其內部包裝了引用。python
成員函數get()、get_pointer()分別能夠得到被包裝的引用和其指針。使用須要包含頭文件"boost/ref.hpp"。c++
#include "boost/ref.hpp" #include <cassert> int main() { int x = 5; boost::reference_wrapper<int> rw(x); rw.get() = 10; //得到引用 *rw.get_pointer() = 15; //得到指針 int n = rw; //隱式轉換爲int assert(x == rw); //隱式轉換爲int rw = 20; //錯誤!引用包裝器不能做爲左值 (int&)rw = 20; //顯示轉換爲int&,這樣能夠做爲左值 assert(x == 20); boost::reference_wrapper<int> rw2(rw); //拷貝構造 rw.get() = 25; assert(rw2.get() == 25);//rw2也是x的一個引用對象 return 0; }
模板類is_reference_wrapper<T>用來判斷類型T是不是一個reference_wrapper類型:經過其成員變量value。算法
模板類unwrap_reference<T>用來得到類型T的真實類型:經過其內部類型定義type。c#
#include "boost/ref.hpp" #include <cassert>
int main() { int n = 10; boost::reference_wrapper<int> rw(n); assert(boost::is_reference_wrapper<decltype(rw)>::value); assert(!boost::is_reference_wrapper<decltype(n)>::value); string str; boost::reference_wrapper<string> rws(str); cout << typeid(boost::unwrap_reference<decltype(rws)>::type).name() << endl; return 0; }
使用函數ref()和cref()能夠很方便的構造reference_wrapper和const reference_wrapper對象,它們能夠根據參數的類型推導出引用的類型。app
除了成員函數get(),工具函數unwrap_ref()也能夠得到引用包裝器內包裝的引用,並且其參數也能夠不是引用包裝器類型,這時候它直接返回參數的引用。ide
#include "boost/ref.hpp" #include <cassert>
int main() { int x = 5; auto rw = boost::ref(x); //使用ref()定義了一個reference_wrapper對象
rw.get() = 10;//得到引用
boost::unwrap_ref(rw) = 15; //得到引用
assert(rw == 15); //隱式轉換
return 0; }
能夠把reference_wrapper類型對象直接賦值給對應類型的變量,reference_wrapper類型能夠隱式轉化爲相對應類型:函數
int i = 10; int n = ref(i); //隱式轉換爲int
reference_wrapper類型對象不能直接做爲左值當作被包裝的引用來賦值使用,若是要對被包裝的引用賦值的話有三種方法:工具
①、ref(x).get() = 10; //get()得到內部引用來做爲左值 ②、(int&)ref(x) = 10; //指定顯示轉換來做爲左值 ④、unwrap_ref(ref(x)) = 10; //unwrap_ref()得到內部引用來做爲左值
二、ref做用1spa
對於一個模板函數,函數調用時其具體類型能夠爲一個引用包裝器類型,eg:
#include "boost/ref.hpp" template<typename T> void TestFun(T n) { boost::unwrap_ref(n) = 10; //T類型多是引用包裝reference_wrapper類型,因此應該使用unwrap_ref } int main() { int num = 0; //TestFun(num); //輸出爲0 TestFun(boost::ref(num)); //輸出爲10 return 0; }
當調用TestFun()時傳入的是變量num則TestFun()爲值傳遞,輸出爲0,傳入的是引用包裝類型則TestFun()爲引用傳遞,輸出爲10。
三、ref做用2
STL中的算法大量使用了函數對象做爲謂詞參數,好比下面示例的for_each()算法:
#include <vector> #include <algorithm> #include "boost/assign.hpp"
using namespace boost::assign; class Square { public: void operator()(int& x) { x = x * x; } }; int main() { vector<int> v = list_of(1) (2) (3) (4); for_each(v.begin(), v.end(), Square()); auto iter = v.begin(), iterEnd = v.end(); for (; iter != iterEnd; iter++) cout << *iter << endl; return 0; }
上面的for_each()中謂詞對象參數就是拷貝傳參,即值傳遞。有的時候函數對象的拷貝代價太高(內部狀態複雜),或者咱們不但願拷貝對象(防止內部狀態改變),或者拷貝是禁止的(noncopyable、單件),這時候咱們能夠傳入函數對象的ref()引用包裝器類型,eg:
#include <vector> #include <algorithm> #include <functional> #include "boost/assign.hpp"
using namespace boost::assign; class Square { public: void operator()(int& x) { x = x * x; } }; int main() { Square sq; vector<int> v = list_of(1) (2) (3) (4); for_each(v.begin(), v.end(), ref(sq)); auto iter = v.begin(), iterEnd = v.end(); for (; iter != iterEnd; iter++) cout << *iter << endl; return 0; }
以上代碼咱們直接使用了ref(),由於C++11中已經包含了ref庫,使用時包含頭文件<functional>便可。boost中的ref不支持對函數對象構造引用包裝器類型,C++11中的ref沒有這種限制。
四、ref做用3
bind採用拷貝的方式存儲綁定的參數,以下爲使用count_if()算法來得到容器中元素長度小於5的元素個數,bind綁定len到仿函數的第二個參數,len參數是值傳遞,即便在operator()中被聲明爲了int&:
#include "boost/bind.hpp" class CLenShorterThan { public: bool operator() (const string& str, int& len) { int iLen = len; len = 0; return str.length() < iLen; } typedef bool result_type; }; int main() { vector<string> myVector = list_of("c++") ("c#") ("python"); int len = 5; int count = count_if(myVector.begin(), myVector.end(), bind(CLenShorterThan(), _1, len)); cout << len << endl; //輸出爲5 return 0; }
能夠給bind綁定的參數傳入ref()引用包裝類型,使參數爲引用傳遞:
#include "boost/bind.hpp" class CLenShorterThan { public: bool operator() (const string& str, int& len) { int iLen = len; len = 0; return str.length() < iLen; } typedef bool result_type; }; int main() { vector<string> myVector = list_of("c++") ("c#") ("python"); int len = 5; int count = count_if(myVector.begin(), myVector.end(), bind(CLenShorterThan(), _1, ref(len))); cout << len << endl; //輸出爲0 return 0; }
五、ref做用4
function使用拷貝語義來保存函數或函數對象,當函數或函數對象很複雜或者禁止拷貝的時候能夠使用ref()以解決拷貝的代價和問題。具體示例可參見文章:boost--function中使用function對象存儲函數對象用於回調的示例代碼。