• [C++ 2011 STL (VS2012 Update4) 源代码阅读系列(2)]熟悉一些宏定义和模版偏特化或叫模版专门化


    [C++ 2011 STL (VS2012 Update4) 源代码阅读系列(2)]熟悉一些宏定义和模版偏特化或叫模版专门化


    // point_test.cpp : 知识点练习和测试,用于单步调试,跟踪。
    //

    #include "stdafx.h"
    #include <functional>
    #include <string>
    #include <iostream>

    using namespace std;
     //for _1, _2, _3...
    using namespace std::placeholders;

    template<class T1,class T2> const T1 my_strcat(const T1 &t1,const T2 &t2)
    {
        return std::move(t1 + t2);
    }

    /*
    测试例子演示了std::bind 和 std:function 的各种组合以及调用的方式
    如果你的编译器编译失败,请尽可能的先去掉 const 后编译,如果全部去掉后
    还是编译失败,请把你的编译器升级到最高版本或者换了它。
    */
    void test_bind()
    {
        std::string s1 = "aaa",s2 = "BBB",ss = "";
        ss = std::bind(my_strcat<std::string,std::string>,s1,s2)();
        std::cout<<ss<<endl;
        ss = my_strcat<std::string,std::string>(s1,s2);
        std::cout<<ss<<endl;
        std::function<const std::string (std::string,std::string)> f1 ;
        f1 = std::bind(my_strcat<std::string,std::string>,_1,_2);
        ss = f1(s1,s2);
        std::cout<<ss<<endl;
        std::function<std::string ()> f2;
        f2 = std::bind(my_strcat<const std::string,std::string>,s1,s2);
        ss = f2();
        std::cout<<ss<<endl;  
    }

    int _tmain(int argc, _TCHAR* argv[])
    {
        test_bind();

        system("pause");
        return 0;
    }

    /*输出结果是:

    aaaBBB
    aaaBBB
    aaaBBB
    aaaBBB
    请按任意键继续. . .


    */

    为了比较熟练的看懂各式各样的宏定义,现在先举出一个推导的例子。我们这里以 std::function 的
    源代码为例逐步展开,追根溯源,其间各种模版和宏定义令你目不暇接,叹为观止。
    0. 总体流程
    总体来看,宏定义
    _VARIADIC_EXPAND_0X(_CLASS_GET_FUNCTION_IMPL_CALLS, , , , )
    是6个宏定义
    _VARIADIC_CALL_OPT_X1,而每个_VARIADIC_CALL_OPT_X1又是3个模板类 _Get_function_impl 的定义
    所以6 *3 总计是18个_Get_function_impl的定义

    1. std::function 定义
    std::function 申明如下
     // TEMPLATE CLASS function
    template<class _Fty>
     class function
      : public _Get_function_impl<_Fty>::type
     { // wrapper for callable objects
    public:
     typedef function<_Fty> _Myt;
     typedef typename _Get_function_impl<_Fty>::type _Mybase;

     function() _NOEXCEPT
      { // construct empty function wrapper
      this->_Reset();
      }
      
      ......省略部分定义和实现
      
      //上面的的代码就调用了这个赋值函数
      template<class _Fx>
      _Myt& operator=(_Fx&& _Func)
      { // move function object _Func
      this->_Tidy();
      this->_Reset(_STD forward<_Fx>(_Func));
      return (*this);
      }
      
      ......省略部分定义和实现
      
    private:
     template<class _Fty2>
      void operator==(const function<_Fty2>&); // not defined
     template<class _Fty2>
      void operator!=(const function<_Fty2>&); // not defined
     };

    我们重点关注申明这句 template<class _Fty> class function : public _Get_function_impl<_Fty>::type,
     _Get_function_impl<_Fty>::type 何许人也,能当它的父类?
       
    2.  _Get_function_impl<_Fty>
    我们继续追踪,有如下定义
    template<class _Tx> struct _Get_function_impl;
    那不对啊,上面的定义应该不是全部的 _Get_function_impl定义。怀疑何在呢?我们看std::function 类
    里面的移动赋值运算符 template<class _Fx> _Myt& operator=(_Fx&& _Func),里面的实现调用了
    _Tidy(),this->_Reset(_STD forward<_Fx>(_Func));这些函数std::function 里面都没有实现啊,那只有一种可能,
    是父类里面实现了这些函数,但是我们看到_Get_function_impl类并没有任何实现啊。那实现到哪里去了呢?那父
    类还有那些诡异的东东呢?  下面熊出没,注意!!!

    3. 追踪 _Get_function_impl
    我们看到 _Get_function_impl 没有任何实现,下面还有几个名称比较类似宏定义。
    #define _CLASS_GET_FUNCTION_IMPL(
     TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, CALL_OPT, X2, X3, X4)
    template<class _Ret COMMA LIST(_CLASS_TYPE)>
     struct _Get_function_impl<_Ret CALL_OPT (LIST(_TYPE))>
     { /* determine type from argument list */
     typedef _Func_class<_Ret COMMA LIST(_TYPE)> type;
     };

    #define _CLASS_GET_FUNCTION_IMPL_CALLS(
     TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, CALL_OPT, X2, X3, X4)
      _VARIADIC_CALL_OPT_X1(_CLASS_GET_FUNCTION_IMPL,
       TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, __cdecl, X2, X3, X4)

    _VARIADIC_EXPAND_0X(_CLASS_GET_FUNCTION_IMPL_CALLS, , , , )

    我们展开看看,里面有何端倪。

    4. 展开 _VARIADIC_EXPAND_0X
    我们继续追,在文件 xstddef 里面,我们发现了它的定义。xstddef 是公共的STL 实现的定义,从
    文件名称可以明显的看出功能。
     // for 0-X args
    #define _VARIADIC_EXPAND_0X(FUNC, X1, X2, X3, X4)
     _VARIADIC_EXPAND_0(FUNC, X1, X2, X3, X4)
     _VARIADIC_EXPAND_1X(FUNC, X1, X2, X3, X4)

    继续展开 _VARIADIC_EXPAND_0 和 _VARIADIC_EXPAND_1X

    我们把 _VARIADIC_EXPAND_1X 也全部展开
    #define _VARIADIC_EXPAND_1X(FUNC, X1, X2, X3, X4)
     _VARIADIC_EXPAND_1(FUNC, X1, X2, X3, X4)
     _VARIADIC_EXPAND_2X(FUNC, X1, X2, X3, X4)

     继续展开_VARIADIC_EXPAND_2X,注意,这里标明了最大支持5个函数参数,这个就是
     为什么 std::function 最大支持5个函数参数。
     
     #if _VARIADIC_MAX == 5
    #define _VARIADIC_EXPAND_2X _VARIADIC_EXPAND_25
    #define _VARIADIC_EXPAND_25(FUNC, X1, X2, X3, X4)
     _VARIADIC_EXPAND_2(FUNC, X1, X2, X3, X4)
     _VARIADIC_EXPAND_3(FUNC, X1, X2, X3, X4)
     _VARIADIC_EXPAND_4(FUNC, X1, X2, X3, X4)
     _VARIADIC_EXPAND_5(FUNC, X1, X2, X3, X4)

    _VARIADIC_EXPAND_0 最终展开就是这个定义了
    // call FUNC(TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, X1, X2, X3, X4)
    #define _VARIADIC_EXPAND_0(FUNC, X1, X2, X3, X4)
    FUNC(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , X1, X2, X3, X4)

    _VARIADIC_EXPAND_1 最终展开就是这个定义了
    #define _VARIADIC_EXPAND_1(FUNC, X1, X2, X3, X4)
    FUNC(_TEM_LIST1, _PAD_LIST1, _RAW_LIST1, _COMMA, X1, X2, X3, X4)

    结果全部出来了
    #define _VARIADIC_EXPAND_2(FUNC, X1, X2, X3, X4)
    FUNC(_TEM_LIST2, _PAD_LIST2, _RAW_LIST2, _COMMA, X1, X2, X3, X4)

    #define _VARIADIC_EXPAND_3(FUNC, X1, X2, X3, X4)
    FUNC(_TEM_LIST3, _PAD_LIST3, _RAW_LIST3, _COMMA, X1, X2, X3, X4)

    #define _VARIADIC_EXPAND_4(FUNC, X1, X2, X3, X4)
    FUNC(_TEM_LIST4, _PAD_LIST4, _RAW_LIST4, _COMMA, X1, X2, X3, X4)

    #define _VARIADIC_EXPAND_5(FUNC, X1, X2, X3, X4)
    FUNC(_TEM_LIST5, _PAD_LIST5, _RAW_LIST5, _COMMA, X1, X2, X3, X4) 
     
    这样,我们获取到6(索引0~5)个类似 _VARIADIC_EXPAND_ 的定义。它们最终是宏定义。
    _VARIADIC_EXPAND_0(_CLASS_GET_FUNCTION_IMPL_CALLS, , , , )
    _VARIADIC_EXPAND_1(_CLASS_GET_FUNCTION_IMPL_CALLS, , , , )
    ...
    _VARIADIC_EXPAND_5(_CLASS_GET_FUNCTION_IMPL_CALLS, , , , )

    我们以索引为 0 的宏定义展开为例。
    _VARIADIC_EXPAND_0(_CLASS_GET_FUNCTION_IMPL_CALLS, , , , ) 展开,那对应的替换就是
    // call FUNC(TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, X1, X2, X3, X4)
    #define _VARIADIC_EXPAND_0(FUNC, X1, X2, X3, X4)
    FUNC(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , X1, X2, X3, X4)

    展开后就是
    _VARIADIC_EXPAND_0(_CLASS_GET_FUNCTION_IMPL_CALLS, , , , )
    就是
    _CLASS_GET_FUNCTION_IMPL_CALLS(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , X1, X2, X3, X4)
    但是这样展开后,我们还是没有看到一个任何类的定义和实现,那继续...


    5. 宏 _CLASS_GET_FUNCTION_IMPL_CALLS
    #define _CLASS_GET_FUNCTION_IMPL_CALLS(
     TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, CALL_OPT, X2, X3, X4)
      _VARIADIC_CALL_OPT_X1(_CLASS_GET_FUNCTION_IMPL,
       TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, __cdecl, X2, X3, X4)
    通过定义,我们展开 _CLASS_GET_FUNCTION_IMPL_CALLS 宏。还是以索引 0的为例,能得到下面
    的定义:
    _VARIADIC_CALL_OPT_X1(_CLASS_GET_FUNCTION_IMPL, _TEM_LIST0, _PAD_LIST0, _RAW_LIST0,,__cdecl,X2, X3, X4)

    6. 宏_VARIADIC_CALL_OPT_X1
    我们来看看这个嵌套在里面的宏.
    #define _VARIADIC_CALL_OPT_X1(FUNC, X1, X2, X3, X4,
     CALL_OPT, X6, X7, X8)
      FUNC(X1, X2, X3, X4, CALL_OPT, X6, X7, X8)
      FUNC(X1, X2, X3, X4, __stdcall, X6, X7, X8)
      FUNC(X1, X2, X3, X4, __fastcall, X6, X7, X8)

    那实际上展开就是3个如下的宏定义
    _CLASS_GET_FUNCTION_IMPL(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , __cdecl,X2, X3, X4)
    _CLASS_GET_FUNCTION_IMPL(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , __stdcall,X2, X3, X4)
    _CLASS_GET_FUNCTION_IMPL(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , __fastcall,X2, X3, X4)

    7. 宏 _CLASS_GET_FUNCTION_IMPL
    我们来看 _CLASS_GET_FUNCTION_IMPL 的定义
    #define _CLASS_GET_FUNCTION_IMPL(
     TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, CALL_OPT, X2, X3, X4)
    template<class _Ret COMMA LIST(_CLASS_TYPE)>
     struct _Get_function_impl<_Ret CALL_OPT (LIST(_TYPE))>
     { /* determine type from argument list */
     typedef _Func_class<_Ret COMMA LIST(_TYPE)> type;
     
     };
     
    8. 获取原型
    结合上面对宏_CLASS_GET_FUNCTION_IMPL的使用,我们能大致获取到下面的定义,我们以
    _CLASS_GET_FUNCTION_IMPL(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , __cdecl,X2, X3, X4)
    为例展:
    template<class _Ret  _RAW_LIST0(_CLASS_TYPE)>
     struct _Get_function_impl<_Ret __cdecl (_RAW_LIST0(_TYPE))>
     { /* determine type from argument list */
     typedef _Func_class<_Ret _RAW_LIST0(_TYPE)> type;
     };
     
      #define _RAW_LIST0(MAP)
      #define _VAR_VAL(NUM) _V ## NUM
    #define _VAR_TYPE(NUM) _V ## NUM ## _t
    #define _CLASS_TYPE(NUM) class _VAR_TYPE(NUM)

    template<class _Ret> struct _Get_function_impl<_Ret __cdecl()>
    {
     typedef _Func_class<_Ret)> type;
    };


    _CLASS_GET_FUNCTION_IMPL(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , __stdcall,X2, X3, X4)
    _CLASS_GET_FUNCTION_IMPL(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , __fastcall,X2, X3, X4)
    对应就是

    template<class _Ret> struct _Get_function_impl<_Ret __stdcall()>
    {
     typedef _Func_class<_Ret)> type;
    };

    template<class _Ret> struct _Get_function_impl<_Ret __fastcall()>
    {
     typedef _Func_class<_Ret)> type;
    };

    9. 我们以 _VARIADIC_EXPAND_2 为例来再推导一次

    _VARIADIC_EXPAND_0X(_CLASS_GET_FUNCTION_IMPL_CALLS, , , , )
    开始,得到
    #define _VARIADIC_EXPAND_2(FUNC, X1, X2, X3, X4)
    FUNC(_TEM_LIST2, _PAD_LIST2, _RAW_LIST2, _COMMA, X1, X2, X3, X4)
    可以得到
    _CLASS_GET_FUNCTION_IMPL_CALLS(_TEM_LIST2, _PAD_LIST2, _RAW_LIST2, _COMMA, X1, X2, X3, X4)
    进而得到
    _VARIADIC_CALL_OPT_X1(_CLASS_GET_FUNCTION_IMPL, _TEM_LIST2, _PAD_LIST2, _RAW_LIST2, _COMMA,__cdecl, X2, X3, X4)
    继续展开,得到
    _CLASS_GET_FUNCTION_IMPL(_TEM_LIST2,_PAD_LIST2,_RAW_LIST2,_COMMA,__cdecl,X2, X3, X4)
    _CLASS_GET_FUNCTION_IMPL(_TEM_LIST2,_PAD_LIST2,_RAW_LIST2,_COMMA,__stdcall,X2, X3, X4)
    _CLASS_GET_FUNCTION_IMPL(_TEM_LIST2,_PAD_LIST2,_RAW_LIST2,_COMMA,__fastcall,X2, X3, X4)
    继续展开,得到(先用__cdecl为例)
    #define _CLASS_GET_FUNCTION_IMPL(
     TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, CALL_OPT, X2, X3, X4)
    template<class _Ret _COMMA _RAW_LIST2(_CLASS_TYPE)>
     struct _Get_function_impl<_Ret __cdecl (_RAW_LIST2(_TYPE))>
     { /* determine type from argument list */
     typedef _Func_class<_Ret _COMMA _RAW_LIST2(_TYPE)> type;
     };

    #define _RAW_LIST2(MAP) MAP(0) _COMMA MAP(1)
    #define _RAW_LIST0(MAP)
    #define _RAW_LIST2(MAP) MAP(0) _COMMA MAP(1)
    #define _VAR_VAL(NUM) _V ## NUM
    #define _VAR_TYPE(NUM) _V ## NUM ## _t
    #define _CLASS_TYPE(NUM) class _VAR_TYPE(NUM)
    #define _TYPE(NUM)  _VAR_TYPE(NUM)

    全部继续展开,
    template<class _Ret , class _V0_t class _V1_t>  
    struct _Get_function_impl<_Ret __cdecl (_V0_t,_V1_t))>
    {
     typedef _Func_class<_Ret, _V0_t,_V1_t> type;
    };

    template<class _Ret , class _V0_t class _V1_t>  
    struct _Get_function_impl<_Ret __cdecl (_V0_t,_V1_t))>
    {
     typedef _Func_class<_Ret, _V0_t,_V1_t> type;
    };

    template<class _Ret , class _V0_t class _V1_t>  
    struct _Get_function_impl<_Ret __stdcall (_V0_t,_V1_t))>
    {
     typedef _Func_class<_Ret, _V0_t,_V1_t> type;
    };  

    10. 我们发现,
    _VARIADIC_EXPAND_0 对应的是类似这样的定义
    template<class _Ret> struct _Get_function_impl<_Ret __stdcall()>
    {
     typedef _Func_class<_Ret)> type;
    };

    _VARIADIC_EXPAND_1 对应的是类似这样的定义
    template<class _Ret,_V0_t> struct _Get_function_impl<_Ret __stdcall(_V0_t)>
    {
     typedef _Func_class<_Ret,_V0_t)> type;
    };

    _VARIADIC_EXPAND_2 对应的是类似这样的定义
    template<class _Ret,_V0_t,_V1_t> struct _Get_function_impl<_Ret __stdcall(_V0_t,_V1_t)>
    {
     typedef _Func_class<_Ret,_V0_t,_V1_t)> type;
    };

    _VARIADIC_EXPAND_5 对应的是类似这样的定义,5表示有5个参数
    template<class _Ret,_V0_t,_V1_t,_V2_t,_V3_t,_V4_t> struct _Get_function_impl<_Ret __stdcall(_V0_t,_V1_t,_V2_t,_V3_t,_V4_t)>
    {
     typedef _Func_class<_Ret,_V0_t,_V1_t,_V2_t,_V3_t,_V4_t)> type;
    };

    自此,全部推导结束,也就能理解类是构造的了。

  • 相关阅读:
    我的.emacs配置文件
    C语言夜未眠5——变量前缀代表的含义
    c语言夜未眠4——对某一位或几位进行反转
    指针也可这么玩:返回局部指针变量,局部噢
    lua学习之table类型
    10个最“优秀”的代码注释
    为什么我希望用C而不是C++来实现ZeroMQ
    c语言夜未眠2——实现撤销和重做
    emacs学习笔记(基本概念)
    flutter json_serializable
  • 原文地址:https://www.cnblogs.com/riskyer/p/3246744.html
Copyright © 2020-2023  润新知