• std..tr1如何传递引用类型给function


    一、问题
    在常规的函数调用中,通常是直接看到函数的定义并调用该函数,所以,函数调用传递的是值还是引用是根据函数声明来决定的。但是,在std::tr1中的bind函数本身是为了完成不同格式参数的适配,所以函数调用处看到的内容和真正的函数执行位置看到的内容并不相同。
    简单的说,这里可以简单的模拟下bind的实现方法
    tsecer@harry: cat tr1_ref.cpp 
     
    template<typename T, typename F>
    int foo(F f, T t)
    {
    return f(t);
    }
     
    typedef int(*funtype)(int &, int);
     
    struct adaptor
    {
    funtype m_fun;
    int m_arg;
    adaptor(funtype f, int y)
    :m_fun(f), m_arg(y)
    {}
     
    int operator()(int x)
    {
    return m_fun(x, m_arg);
    }
    };
     
    int bar(int &x, int y)
    {
    return x + y;
    }
     
    int main()
    {
    int x =1, y =2;
    adaptor a(bar, y);
    foo(a, x);
    }
    tsecer@harry: g++ tr1_ref.cpp
    tsecer@harry: 
     
    在上面的例子中,adaptor a(bar, y) 语句生成的局部变量就相当于是 tr1::bind生成的中间变量类型,可以看到的是,虽然bar函数声明自己的第一个参数是一个引用类型,但是在adaptor类中,它依然只是把它作为一个值保存起来,进而在调用bar函数的时候,传入的是一个复制的值而不是引用,所以导致最终并不是希望的结果。
    二、gcc的std库如何解决这个问题
    1、引入特殊ref类型
      template<typename _Tp>
        class reference_wrapper
          : public _Reference_wrapper_base<typename remove_cv<_Tp>::type>
        {
          // If _Tp is a function type, we can't form result_of<_Tp(...)>,
          // so turn it into a function pointer type.
          typedef typename _Function_to_function_pointer<_Tp>::type
            _M_func_type;
     
          _Tp* _M_data;
        public:
          typedef _Tp type;
          explicit reference_wrapper(_Tp& __indata): _M_data(&__indata)
          { }
     
          reference_wrapper(const reference_wrapper<_Tp>& __inref):
          _M_data(__inref._M_data)
          { }
     
          reference_wrapper&
          operator=(const reference_wrapper<_Tp>& __inref)
          {
            _M_data = __inref._M_data;
            return *this;
          }
     
          operator _Tp&() const
          { return this->get(); }
     
          _Tp&
          get() const
          { return *_M_data; }
     
    #define _GLIBCXX_REPEAT_HEADER <tr1/ref_wrap_iterate.h>
    #include <tr1/repeat.h>
    #undef _GLIBCXX_REPEAT_HEADER
        };
      // Denotes a reference should be taken to a variable.
      template<typename _Tp>
        inline reference_wrapper<_Tp>
        ref(_Tp& __t)
        { return reference_wrapper<_Tp>(__t); }
     
    在其基类reference_wrapper中,其拷贝构造函数有一个这样的声明
          typedef _Tp type;
          explicit reference_wrapper(_Tp& __indata): _M_data(&__indata)
          { }
    也就是用匹配类型给变量初始化的时候,把其地址保存在自己的_M_data中,而不是保存自己独立的一份数据,所以可以达到引用的效果。
    2、在参数提取中
    特例化参数为reference_wrapper类型的_Mu模版,从而在参数提取时调用__arg.get(),这个时候就可以返回引用类型。
    gcc-4.1.0libstdc++-v3include r1functional
     
      template<typename _Arg,
               bool _IsBindExp = is_bind_expression<_Arg>::value,
               bool _IsPlaceholder = (is_placeholder<_Arg>::value > 0)>
        class _Mu;
     
      /**
       *  @if maint
       *  If the argument is reference_wrapper<_Tp>, returns the
       *  underlying reference. [TR1 3.6.3/5 bullet 1]
       *  @endif
       */
      template<typename _Tp>
        class _Mu<reference_wrapper<_Tp>, false, false>
        {
        public:
          typedef _Tp& result_type;
     
          /* Note: This won't actually work for const volatile
           * reference_wrappers, because reference_wrapper::get() is const
           * but not volatile-qualified. This might be a defect in the TR.
           */
          template<typename _CVRef, typename _Tuple>
          result_type
          operator()(_CVRef& __arg, const _Tuple&) const volatile
          { return __arg.get(); }
        };
     
    三、使用tr1库看下效果
    可以看到,如果不使用 tr1::ref封装x,那么虽然bind的函数参数使用的是引用,但是最终的结果依然没有修改到传入的参数x。
    tsecer@harry: cat usetr1.cpp 
    #include <tr1/functional>
    #include <stdio.h>
     
    using namespace std;
    typedef tr1::function<void(int &)>  ff;
     
    void foo(int &x)
    {
     x *= 10;
    }
     
    int main()
    {
      int x = 1;
      tr1::bind(foo, x)();
      printf("x %d ", x);
      tr1::bind(foo, tr1::ref(x))();
      printf("x %d ", x);
    }
    tsecer@harry: g++ usetr1.cpp
    tsecer@harry: ./a.out 
    x 1
    x 10
  • 相关阅读:
    [编译器] GCC编译过程 [ISO > ESc]
    《计算机网络 4》 应用层
    [编译器] cc、gcc、g++、CC的区别概括
    这个VS2010 技巧 折磨了我好久。留个贴纪念下。
    C#设置系统日期和时间的代码
    C# string格式的日期时间字符串转为DateTime类型
    中文普通图书著者号码的取号规定
    汉语著者号自动生成系统的设计与实现
    网络环境下提高图书编目工作效率搞高的方法
    jquery 超级select 插件 selectsearch v3.0.0.0插件 支持汉字、拼音、英文快速定位查询的超级select插件。可方向键、tab 键快速选择。
  • 原文地址:https://www.cnblogs.com/tsecer/p/10488041.html
Copyright © 2020-2023  润新知