zoukankan      html  css  js  c++  java
  • [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;
    };

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

  • 相关阅读:
    Get distinct count of rows in the DataSet
    单引号双引号的html转义符
    PETS Public English Test System
    Code 39 basics (39条形码原理)
    Index was outside the bounds of the array ,LocalReport.Render
    Thread was being aborted Errors
    Reportviewer Error: ASP.NET session has expired
    ReportDataSource 值不在预期的范围内
    .NET/FCL 2.0在Serialization方面的增强
    Perl像C一样强大,像awk、sed等脚本描述语言一样方便。
  • 原文地址:https://www.cnblogs.com/riskyer/p/3246744.html
Copyright © 2011-2022 走看看