zoukankan      html  css  js  c++  java
  • boost--ref

    1、ref简介

      reference_wrapper包含在ref库中,它是引用包装器类型,即其内部包装了引用。

      成员函数get()、get_pointer()分别可以获得被包装的引用和其指针。使用需要包含头文件"boost/ref.hpp"。

    #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;
    }
    View Code

      模板类is_reference_wrapper<T>用来判断类型T是否是一个reference_wrapper类型:通过其成员变量value。

      模板类unwrap_reference<T>用来获得类型T的真实类型:通过其内部类型定义type。

    #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;
    }
    View Code

      使用函数ref()和cref()可以很方便的构造reference_wrapper和const reference_wrapper对象,它们可以根据参数的类型推导出引用的类型。

      除了成员函数get(),工具函数unwrap_ref()也可以获得引用包装器内包装的引用,而且其参数也可以不是引用包装器类型,这时候它直接返回参数的引用。

    #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;
    }
    View Code

      可以把reference_wrapper类型对象直接赋值给对应类型的变量,reference_wrapper类型可以隐式转化为相对应类型:

    int i = 10;
    int n = ref(i); //隐式转换为int
    View Code

      reference_wrapper类型对象不能直接作为左值当做被包装的引用来赋值使用,如果要对被包装的引用赋值的话有三种方法:

    ①、ref(x).get() = 10; //get()获得内部引用来作为左值
    ②、(int&)ref(x) = 10; //指定显示转换来作为左值
    ④、unwrap_ref(ref(x)) = 10; //unwrap_ref()获得内部引用来作为左值
    View Code

    2、ref作用1

      对于一个模板函数,函数调用时其具体类型可以为一个引用包装器类型,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;
    }
    View Code

      当调用TestFun()时传入的是变量num则TestFun()为值传递,输出为0,传入的是引用包装类型则TestFun()为引用传递,输出为10。

    3、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;
    }
    View Code

      上面的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;
    }
    View Code

      以上代码我们直接使用了ref(),因为C++11中已经包含了ref库,使用时包含头文件<functional>即可。boost中的ref不支持对函数对象构造引用包装器类型,C++11中的ref没有这种限制。

    4、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;
    }
    View Code

      可以给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;
    }
    View Code

     5、ref作用4

     function使用拷贝语义来保存函数或函数对象,当函数或函数对象很复杂或者禁止拷贝的时候可以使用ref()以解决拷贝的代价和问题。具体示例可参见文章:boost--function中使用function对象存储函数对象用于回调的示例代码。

     

  • 相关阅读:
    P4555 [国家集训队]最长双回文串(回文树)
    【洛谷 P3805】 【模板】manacher算法
    【洛谷 P2485】 [SDOI2011]计算器 (BSGS)
    【洛谷 P3846】 [TJOI2007]可爱的质数 (BSGS)
    【洛谷 P1712】 [NOI2016]区间 (线段树+尺取)
    【洛谷 P1251】 餐巾计划问题 (费用流)
    【洛谷 P1337】[JSOI2004]平衡点 / 吊打XXX (模拟退火)
    【POJ 1719】 Shooting Contest (二分图匹配)
    【洛谷 P1631】 序列合并 (堆)
    【洛谷 P2515】 [HAOI2010]软件安装 (缩点+树形背包)
  • 原文地址:https://www.cnblogs.com/milanleon/p/7482989.html
Copyright © 2011-2022 走看看