[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;
};
自此,全部推導結束,也就能理解類是構造的了。