也许是我不适应的原因,在visual c++中std::tr1的代码比stl明显难读了很多。 对于可接受多个参数的function,用错之后,那个错误信息看得是云里雾里。原因是这份代码中使用了大量的宏来辅助多个参数的实现。
晚上花了不少时间弄清楚宏的问题。
以std::tr1::mem_fn为例,对于每一个可接受多参数的function, 都有类似实现:
#define _INCL_FILE <xxmem_fn>
#include <xfwrap>
其中xxmem_fn是真正的实现,里面使用了大量让人头晕的宏。 <xfwrap>是tricky。真是服了dinkumware的人,想出这样的创举。估计他们平时调试也很郁闷:)。难道现在还是P.J. Plauger一个人完成库的实现?反正版权信息上只有他名字。
下面是对几个相关有文件的粗略分析,知道这些,应该可以阅读实现代码了。下面的内容仅作参考,这只是推断和猜测的结果。
<xfwrap>
iterator 0 to N to include <xfwrap1>
<xtr1common>
#define _XNAME(x, z) x ## z
#define _YNAME(x, z) _XNAME(x, z)
#define _YNAME15(x, y, z) _XNAME(x, z) y
#define _YNAME2(x, y, z) _XNAME(x, z) _XNAME(y, z)
#define _CORE_0(x)
#define _CORE_1(x)
#define _CORE_2(x)
#define _CORE_3(x) _YNAME(x, 1)
...
#define _CORE_n(x) _CORE_n-1(x), _YNAME(x, n-2)
#define _CORE15_n(x, y) _CORE_n but in which _YNAME = _YNAME15
#define _CORE2_n(x, y) _CORE_n but in which _YNAME = _YNAME2
ex.
_CORE(X) X1, X2, X3, ..., Xn-2
_CORE15(X, Y) X1 Y, X2 Y, X3 Y, ..., Xn-2 Y
_CORE2(X, Y) X1 Y1, X2 Y2, X3 Y3, ..., Xn-2 Yn-2
#define _NARGSm1_0 0
#define _NARGSm1_1 0
#define _NARGSm1_2 1
...
#define _NARGSm1_n n-1
Used to indicate the last index of the list.
#define _TAIL_N(x)
#define _TAIL_n-1(x) x
#define _TAIL_n-2(x) TAIL_n-1(x), x
...
#define _TAIL_0 TAIL_1(x), x
It will make a list with N-n items. In current tr1 implement, then N is
10. This TAIL(x) will make a list with specific tag x to fill the actual
arguments list. _Nil will be the empty type in this std::tr1 implement.
#define _ARG_MAX 9
#define _CDR_MAX(x) _CORE_10(x), _YNAME(x, _ARG_MAX)
#define _CDR15_MAX(x, y) _CORE15_10(x, y), _YNAME15(x, y, _ARG_MAX)
#define _CDR2_MAX(x, y) _CORE2_10(x, y), _YNAME2(x, y, _ARG_MAX)
#define _LIST_MAX(x) _YNAME(x, 0), _CDR_MAX(x)
#define _LIST15_MAX(x, y) _YNAME15(x, y, 0), _CDR15_MAX(x, y)
#define _LIST2_MAX(x, y) _YNAME2(x, y, 0), _CDR2_MAX(x, y)
#define _CLASS_ARG0_MAX _LIST_MAX(class _Arg)
#define _CLASS_FARG0_MAX _LIST_MAX(class _Farg)
#define _ARG0_A0_REF_MAX _LIST2_MAX(_Arg, &_Ax)
#define _ARG1_ARG2_MAX _CDR_MAX(_Arg)
#define _ARG0_ARG1_MAX _LIST_MAX(_Arg)
#define _FARG1_FARG2_MAX _CDR_MAX(_Farg)
#define _FARG0_FARG1_MAX _LIST_MAX(_Farg)
#define _A1_A2_MAX _CDR_MAX(_Ax)
#define _A0_A1_MAX _LIST_MAX(_Ax)
#define _NIL_TAIL_MAXm1 _TAIL_1(_Nil)
#define _NIL_TAIL_MAX _TAIL_0(_Nil)
#define _TAIL_MAX(x) _TAIL_0(x)
#define _CLASS_ARG0_DEF_MAX _LIST15_MAX(class _Arg, = _Nil)
Many max define. Some rule could be concluded:
list: (first itme with index0, the cdr list wich equal to
core(item)).
class_arg0_list: (class, list), class will be the first member of
the new list.
arg0_arg1_list: equal to list.
arg1_arg2_list: equal to cdr part of list.
<xfwrap1>
item0 _COMMA0 item1 _COMMA1 item2 _MCOMMA item3 _LCOMMA ... itemN-1 _LCOMMA itemN
#define _MCOMMA n >= 2 ? "," : ""
#define _LCOMMA n >= 3 ? "," : ""
#define _FIRST(x) n >= 1 ? _YNAME(x, 0) : ""
#define _FIRSTm1(x) n >= 2 ? _FIRST(x) : ""
_FIRST15*, _FIRST2* are similar to _FIRST
#define _LAST(x) n >= 2 ? _YNAME(x, _NARGSm1) : ""
#define _LAST15(x, y) n >= 2 ? _YNAME15(x, y, _NARGSm1) : ""
#define _LAST2(x, y) n >= 2 ? _YNAME2(x, y, _NARGSm1) : ""
#define _CDR(x) _CORE(x) _LCOMMA _LAST(x)
#define _CDR15(x, y) _CORE15(x, y) _LCOMMA _LAST15(x, y)
#define _CDR2(x, y) _CORE2(x, y) _LCOMMA _LAST2(x, y)
#define _LIST(x) _FIRST(x) _MCOMMA _CDR(x)
#define _LISTm1(x) _FIRSTm1(x) _LCOMMA _CORE(x)
#define _LIST15(x, y) _FIRST15(x, y) _MCOMMA _CDR15(x, y)
#define _LIST15m1(x, y) _FIRST15m1(x, y) _LCOMMA _CORE15(x, y)
#define _LIST2(x, y) _FIRST2(x, y) _MCOMMA _CDR2(x, y)
#define _LIST2m1(x, y) _FIRST2m1(x, y) _LCOMMA _CORE2(x, y)
#define _CLASS_NAME(x) _YNAME(x, _NARGS)
#define _PREV_NAME(x) _YNAME(x, _NARGSm1)
_NARGS is n, from 0 ... N
_NARGSm1 is the lastest index
#define _CLASS_ARG0 _LIST(class _Arg)
#define _CLASS_ARG0m1 _LISTm1(class _Arg)
#define _CLASS_ARG1 _CDR(class _Arg)
#define _CLASS_FARG0 _LIST(class _Farg)
#define _ARG0_ARG1 _LIST(_Arg)
#define _ARG0_ARG1_REF _LIST15(_Arg, &)
#define _ARG0_ARG1_CREF _LIST15(const _Arg, &)
the 5 part is reference tag.
#define _ARG0_ARG1m1 _LISTm1(_Arg)
#define _ARG1_ARG2 _CDR(_Arg)
#define _ARG1_ARG2m1 _CORE(_Arg)
#define _FARG0_FARG1 _LIST(_Farg)
#define _FARG0_FARG1_REF _LIST15(_Farg, &)
#define _FARG0_FARG1_CREF _LIST15(const _Farg, &)
#define _FARG1_FARG2 _CDR(_Farg)
#define _FARG1_FARG2_REF _CDR15(_Farg, &)
#define _FARG1_FARG2_CREF _CDR15(const _Farg, &)
#define _ARG0_A0 _LIST2(_Arg, _Ax)
#define _ARG0_A0_REF _LIST2(_Arg, &_Ax)
#define _ARG0_A0_CREF _LIST2(const _Arg, &_Ax)
#define _FARG1_F1 _CDR2(_Farg, _Fx)
#define _FARG1_F1_REF _CDR2(_Farg, &_Fx)
#define _FARG1_F1_CREF _CDR2(const _Farg, &_Fx)
#define _FARG0_F0 _LIST2(_Farg, _Fx)
#define _FARG0_F0_REF _LIST2(_Farg, &_Fx)
#define _FARG0_F0_CREF _LIST2(const _Farg, &_Fx)
the 2 part is used to indicate type value.
#define _A0_A1 _LIST(_Ax)
#define _F0_F1 _LIST(_Fx)
#define _F1_F2 _CDR(_Fx)
#define _A0_A1m1 _LISTm1(_Ax)
#define _A1_A2m1 _CORE(_Ax)
#define _ARG0_A0_TO_REF _LIST2(typename _Remove_reference<_Arg, >::_Type& _Ax)
#define _ARG0_ARG1_TO_REF _LIST15(typename _Remove_reference<_Arg, >::_Type&)
#define _C_***
add comma0 or comma1 to the list
after define these macros, at last:
#include _INCL_FILE