首页 > 代码库 > 15) .实现可变参数的(成员/非成员)模板函数的回调,消除类似代码

15) .实现可变参数的(成员/非成员)模板函数的回调,消除类似代码

完整的源代码及用法测试代码可以在我的资源中去下载.


C++语法不支持模板函数/模板成员函数作为回调函数,同时把运行期代码向编译期代码转换也只有switch...case或者if..else能够实现。

如果case比较多的时候,代码非常臃肿,而且类似的大片代码中,往往只有一个参数的不同,其它都是相同的。这对于用户来说,都是一个大量的重复性的hard-code性的负担,而且也容易导致出错。


本库采用了封装,可以把运行性的switch...case/if..else分支选择转换为编译期的代码,支持模板函数的回调,并且支持最多6个可变参数(可以简易扩充参数个数),从而可以大幅度地减少代码量,(代码量可以减少到原代码的1/N,N为case数目)。并且由于是编译期代码,从而保证不会出错(出错将导致编译失败)。


并且附带提供了CEnumRange,可以检测一个枚举值是否在枚举范围内。


#ifndef __test_traverseEnum_h_
#define __test_traverseEnum_h_
/***********************************************************************************************************************
* Description         : test file for <utility\traverseEnum.h>
* Author              : Shen.Xiaolong (Shen Tony,2009-2014)
* Mail                : xlshen2002@hotmail.com,  xlshen@126.com
* verified platform   : VS2008 (2014/11/02 11:42:08.21)
* copyright:          : free to use / modify / sale in free and commercial software.
*                       Unique limit: MUST keep those copyright comments in all copies and in supporting documentation.
* usage demo          : #define RUN_EXAMPLE_TRAVERSEENUM to run this demo
***********************************************************************************************************************/
#include "testconfig.h"
#include <utility/traverseEnum.h>
#include "test_macroDef.h"
#include "utility/macroDef.h"
#include "utility/parameterWrp.h"


//#define RUN_EXAMPLE_TRAVERSEENUM


#ifdef COMPILE_EXAMPLE_ALL
    #define COMPILE_EXAMPLE_TRAVERSEENUM
#endif


#ifdef RUN_EXAMPLE_ALL
    #define RUN_EXAMPLE_TRAVERSEENUM
#endif


#if defined(RUN_EXAMPLE_TRAVERSEENUM) && !defined(COMPILE_EXAMPLE_TRAVERSEENUM)
    #define COMPILE_EXAMPLE_TRAVERSEENUM
#endif


////////////////////////////////////////////usage demo code//////////////////////////////////////////////////////////////////
#ifdef COMPILE_EXAMPLE_TRAVERSEENUM


//sequential enum value, it can apply SKIP_ENUM_NEXT except you want to skip some enum value(s)
enum SeqEunm {S_Val_Min,S_Val_1,S_Val_2,S_Val_3,S_Val_4,S_Val_5,S_Val_6,S_Val_7,S_Val_Max};
typedef UtilExt::CEnumRange<SeqEunm,S_Val_Min,S_Val_Max>        SeqEnumRange;
SKIP_ENUM_ONE(SeqEnumRange,S_Val_4);                            //skip 4


//test SKIP_ENUM_ONE
typedef UtilExt::CEnumRange<SeqEunm,S_Val_1,S_Val_6>            SeqEnumSkipOneRange;
// SKIP_ENUM_ONE(SeqEnumSkipOneRange,S_Val_1);                  //fail because S_Val_1 is head of SeqEnumSkipOneRange
// SKIP_ENUM_ONE(SeqEnumSkipOneRange,S_Val_6);                  //fail because S_Val_6 is tail of SeqEnumSkipOneRange
SKIP_ENUM_ONE(SeqEnumSkipOneRange,S_Val_3);                     //OK,   S_Val_3 is not head or tail


//non-sequential enum type : value 2,4 is lack
enum NonSeqEunm
{   
    NS_Val_Min = 0 ,
    NS_Val_1   = 1,
    NS_Val_3   = 3,
    NS_Val_5   = 5,
    NS_Val_8   = 8,
    NS_Val_Max
};
typedef UtilExt::CEnumRange<NonSeqEunm,NS_Val_Min,NS_Val_Max>   NonSeqEnumRange;
//skip NS_Val_3 when traverse enum type "DemoEunm" : jump from NS_Val_2 to NS_Val_4
SKIP_ENUM_MIDDLE(NonSeqEnumRange,NS_Val_1,NS_Val_3);                      //skip 2
SKIP_ENUM_MIDDLE(NonSeqEnumRange,NS_Val_3,NS_Val_5);                      //skip 4
SKIP_ENUM_MIDDLE(NonSeqEnumRange,NS_Val_5,NS_Val_8);                      //skip 6 ,7


//SKIP_ENUM_NEXT(EnumRange,NS_Val_3,NS_Val_1);                    //Fail because  NS_Val_3 > NS_Val_1
//SKIP_ENUM_NEXT(EnumRange,NS_Val_3,DemoEunm(NS_Val_Max+1));      //Fail because  DemoEunm(NS_Val_Max+1) is not in range
namespace DemoUsage
{   
    template<SeqEunm TVal>
    bool globalEnumFunc(int a,char* pStr)
    {
        printf("globalEnumFunc [%d],param=%d,%s",TVal+1,a,pStr?pStr:"NULL");
        return true;
    }
    Declare_Template_Global_CallBack(::DemoUsage::,SeqEunm,globalEnumFunc);


    struct CNonSeqEunmInterface_1
    {
        CNonSeqEunmInterface_1(int p) : m_bResult(false),m_param(p){};


        template<NonSeqEunm TVal>
        void apply()
        {
            dbgOutput(TXT("\n\n[NonSeqEunm]Enum value is %d."),TVal);
            dbgOutput(TXT("\n[CEnumInterface_1::apply] %d"),TVal);
            m_bResult = (TVal+m_param) > NS_Val_Max;
        }


        bool m_bResult;
        int m_param;
    };
    Declare_Template_Mem_CallBack(::DemoUsage::,CNonSeqEunmInterface_1,NonSeqEunm,apply );


    struct CNonSeqEunmInterface_2
    {
        CNonSeqEunmInterface_2(VCHAR* pStr) : m_bResult(false),m_pStr(pStr){};


        template<NonSeqEunm TVal>
        void apply()
        {
            dbgOutput(TXT("\n\n[NonSeqEunm]Enum value is %d."),TVal);
            dbgOutput(TXT("\n[CEnumInterface_2::apply] %s %d"),m_pStr,TVal);
            m_bResult = (TVal+2) > NS_Val_Max;
        }


        bool m_bResult;
        VCHAR* m_pStr;
    };
    Declare_Template_Mem_CallBack(::DemoUsage::,CNonSeqEunmInterface_2,NonSeqEunm,apply );


    struct CSeqEunmInterface_1
    {
        CSeqEunmInterface_1(int p) : m_bResult(false),m_param(p){};


        template<SeqEunm TVal>
        void apply()
        {
            dbgOutput(TXT("\n\n[SeqEunm]Enum value is %d."),TVal);
            dbgOutput(TXT("\n[CSeqEunmInterface_1::apply] %d"),TVal);
            m_bResult = (TVal+m_param) > NS_Val_Max;
        }


        bool m_bResult;
        int m_param;
    };
    Declare_Template_Mem_CallBack(::DemoUsage::,CSeqEunmInterface_1,SeqEunm,apply );


    struct CSeqEunmInterface_2
    {
        CSeqEunmInterface_2(VCHAR* pStr) : m_bResult(false),m_pStr(pStr){};


        template<SeqEunm TVal>
        void apply()
        {
            dbgOutput(TXT("\n\n[SeqEunm]Enum value is %d."),TVal);
            dbgOutput(TXT("\n[CSeqEunmInterface_2::apply] %s %d"),m_pStr,TVal);
            m_bResult = (TVal+2) > NS_Val_Max;
        }


        bool m_bResult;
        VCHAR* m_pStr;
    };
    Declare_Template_Mem_CallBack(::DemoUsage::,CSeqEunmInterface_2,SeqEunm,apply );


    Declare_Template_Mem_CallBack(::DemoUsage::,CTestEnumSuite,SeqEunm,printEnum );
    Declare_Template_Mem_CallBack(::DemoUsage::,CTestEnumSuite,SeqEunm,printNext );
    Declare_Template_Mem_CallBack(::DemoUsage::,CTestEnumSuite,SeqEunm,print2Param );
    Declare_Template_Mem_CallBack(::DemoUsage::,CTestEnumSuite,SeqEunm,inOutParam );
    class CTestEnumSuite
    {
        
    public:
        template<SeqEunm TVal>
        bool printEnum()
        {
            outputTxt((TXT("CTestEnumSuite::printEnum [%d]"),TVal));
            return true;
        }


        template<SeqEunm TVal>
        bool printNext()
        {
            outputTxt((TXT("CTestEnumSuite::printNext [%d]"),TVal+1));
            return true;
        }


        template<SeqEunm TVal>
        void inOutParam(char p1,int& outParam)
        {
            outputTxt((TXT("CTestEnumSuite::inOutParam [%d]"),TVal+1));
            outParam = 4;
        }


        template<SeqEunm TVal>
        bool print2Param(int a,char* pStr)
        {
            printf("CTestEnumSuite::print2Param [%d],param=%d,%s",TVal+1,a,pStr?pStr:"NULL");
            return true;
        }


        void testEntry()
        {
            int a = 5;
            char* pStr = "in testEntry";
            SeqEunm tVal = SeqEunm(rand()%S_Val_Max);


            //test member function
            ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,true>::apply(tVal,CTestEnumSuite_SeqEunm_printEnum<CTestEnumSuite>(),makeParamPackage(*this))));
            ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,true>::apply(tVal,CTestEnumSuite_SeqEunm_printNext<CTestEnumSuite>(),makeParamPackage(*this))));
            ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,true>::apply(tVal,CTestEnumSuite_SeqEunm_print2Param<CTestEnumSuite>(),makeParamPackage(*this,a,pStr))));
            ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,true>::apply(tVal,Template_Mem_Callback_Obj(CTestEnumSuite,SeqEunm,printEnum),makeParamPackage(*this))));
            ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,true>::apply(tVal,Template_Mem_Callback_Obj(CTestEnumSuite,SeqEunm,printNext),makeParamPackage(*this))));
            ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,true>::apply(tVal,Template_Mem_Callback_Obj(CTestEnumSuite,SeqEunm,print2Param),makeParamPackage(*this,a,pStr))));


            //test in-out parameter
            char p1 = 3;
            int outP = 6;
            ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,true>::apply(tVal,Template_Mem_Callback_Obj(CTestEnumSuite,SeqEunm,inOutParam ),makeParamPackage(*this,p1,outP))));
            ASSERT_AND_LOG(6==outP);
            ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,true>::apply(tVal,Template_Mem_Callback_Obj(CTestEnumSuite,SeqEunm,inOutParam ),makeParamPackage(*this,p1,MIOP(outP)))));
            ASSERT_AND_LOG(4==outP);


            //test global function
            ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,true>::apply(tVal,_SeqEunm_globalEnumFunc(),makeParamPackage(a,pStr))));
            ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,true>::apply(tVal,Template_Global_Callback_Obj(SeqEunm,globalEnumFunc),makeParamPackage(a,pStr))));
        }
    };


    


    template<SeqEunm TVal >
    struct TValMap;
    template<>
    struct TValMap<S_Val_6> : public Value2Type<bool (DemoUsage::CTestEnumSuite::*)(void) ,&CTestEnumSuite::printEnum<S_Val_6> > {};


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    inline void showUsage_traverseEnum()
    {
        PrintUsage();


        using namespace UtilExt;
        typedef SeqEnumRange::Min_T                                 SEnumValueMin;
        typedef SeqEnumRange::Max_T                                 SEnumValueMax;
        typedef NonSeqEnumRange::Min_T                              NSEnumValueMin;
        typedef NonSeqEnumRange::Max_T                              NSEnumValueMax;


        //test UtilExt.CEnumRange.Min_T/Max_T
        Static_Assert((CGetEnumValue<typename NonSeqEnumRange::Min_T>::value=http://www.mamicode.com/=NS_Val_Min));
        Static_Assert((CGetEnumValue<typename NonSeqEnumRange::Max_T>::value=http://www.mamicode.com/=NS_Val_Max));
        Static_Assert((CGetEnumValue<typename SeqEnumRange::Min_T>::value=http://www.mamicode.com/=S_Val_Min));
        Static_Assert((CGetEnumValue<typename SeqEnumRange::Max_T>::value=http://www.mamicode.com/=S_Val_Max));


        //test UtilExt.CEnumValue.Next
        Static_Assert((CGetEnumValue<typename CEnumValue<SeqEnumRange,S_Val_1>::Next<true>::type>::value=http://www.mamicode.com/=S_Val_2));
        Static_Assert((CGetEnumValue<typename CEnumValue<SeqEnumRange,S_Val_1>::Next<false>::type>::value=http://www.mamicode.com/=S_Val_Min));
        Static_Assert(!(CGetEnumValue<typename CEnumValue<SeqEnumRange,S_Val_1>::Next<false>::type>::value=http://www.mamicode.com/=S_Val_2));
        Static_Assert((CGetEnumValue<typename CEnumValue<NonSeqEnumRange,NS_Val_1>::Next<true>::type>::value=http://www.mamicode.com/=NS_Val_3));
        Static_Assert((CGetEnumValue<typename CEnumValue<NonSeqEnumRange,NS_Val_1>::Next<false>::type>::value=http://www.mamicode.com/=NS_Val_Min));
        Static_Assert(!(CGetEnumValue<typename CEnumValue<NonSeqEnumRange,NS_Val_1>::Next<false>::type>::value=http://www.mamicode.com/=NS_Val_3));


        //test UtilExt.CEnumValue.Last
        Static_Assert((CGetEnumValue<typename CEnumValue<SeqEnumRange,S_Val_3>::Last<true>::type>::value=http://www.mamicode.com/=S_Val_2));
        Static_Assert((CGetEnumValue<typename CEnumValue<SeqEnumRange,S_Val_3>::Last<false>::type>::value=http://www.mamicode.com/=S_Val_5)); //because SKIP_ENUM_ONE(SeqEnumRange,S_Val_4);
        Static_Assert(!(CGetEnumValue<typename CEnumValue<SeqEnumRange,S_Val_3>::Last<false>::type>::value=http://www.mamicode.com/=S_Val_2));
        Static_Assert((CGetEnumValue<typename CEnumValue<NonSeqEnumRange,NS_Val_3>::Last<true>::type>::value=http://www.mamicode.com/=NS_Val_1));
        Static_Assert((CGetEnumValue<typename CEnumValue<NonSeqEnumRange,NS_Val_3>::Last<false>::type>::value=http://www.mamicode.com/=NS_Val_5));
        Static_Assert(!(CGetEnumValue<typename CEnumValue<NonSeqEnumRange,NS_Val_3>::Last<false>::type>::value=http://www.mamicode.com/=NS_Val_1));


        //test UtilExt.CGetEnumRange
        Static_Assert((IsSameType<typename CGetEnumRange<SEnumValueMin>::type,SeqEnumRange>::value));
        Static_Assert((IsSameType<typename CGetEnumRange<SEnumValueMax>::type,SeqEnumRange>::value));
        Static_Assert((IsSameType<typename CGetEnumRange<CEnumValue<SeqEnumRange,S_Val_3> >::type,SeqEnumRange>::value));
        Static_Assert((IsSameType<typename CGetEnumRange<CEnumValue<SeqEnumRange,S_Val_6> >::type,SeqEnumRange>::value));
        Static_Assert((IsSameType<typename CGetEnumRange<CEnumValue<SeqEnumRange,S_Val_2> >::type,typename CGetEnumRange<CEnumValue<SeqEnumRange,S_Val_1> >::type>::value));
        Static_Assert((IsSameType<typename CGetEnumRange<SEnumValueMax>::type,typename CGetEnumRange<SEnumValueMin>::type>::value));
        Static_Assert((IsSameType<typename CGetEnumRange<NSEnumValueMin>::type,NonSeqEnumRange>::value));
        Static_Assert((IsSameType<typename CGetEnumRange<NSEnumValueMax>::type,NonSeqEnumRange>::value));
        Static_Assert((IsSameType<typename CGetEnumRange<CEnumValue<NonSeqEnumRange,NS_Val_3> >::type,NonSeqEnumRange>::value));
        Static_Assert((IsSameType<typename CGetEnumRange<CEnumValue<NonSeqEnumRange,NS_Val_5> >::type,NonSeqEnumRange>::value));
        Static_Assert((IsSameType<typename CGetEnumRange<CEnumValue<NonSeqEnumRange,NS_Val_Min> >::type,typename CGetEnumRange<CEnumValue<NonSeqEnumRange,NS_Val_1> >::type>::value));
        Static_Assert((IsSameType<typename CGetEnumRange<NSEnumValueMax>::type,typename CGetEnumRange<NSEnumValueMin>::type>::value));


        //test UtilExt.CGetEnumRangeMax/CGetEnumRangeMin
        Static_Assert((CGetEnumRangeMax<CEnumValue<NonSeqEnumRange,NS_Val_3> >::value=http://www.mamicode.com/=NS_Val_Max));
        Static_Assert((CGetEnumRangeMax<CEnumValue<NonSeqEnumRange,NS_Val_5> >::value=http://www.mamicode.com/=NS_Val_Max));
        Static_Assert((CGetEnumRangeMax<CEnumValue<SeqEnumRange,S_Val_3> >::value=http://www.mamicode.com/=S_Val_Max));
        Static_Assert((CGetEnumRangeMax<CEnumValue<SeqEnumRange,S_Val_5> >::value=http://www.mamicode.com/=S_Val_Max));
        Static_Assert((CGetEnumRangeMin<CEnumValue<NonSeqEnumRange,NS_Val_3> >::value=http://www.mamicode.com/=NS_Val_Min));
        Static_Assert((CGetEnumRangeMin<CEnumValue<NonSeqEnumRange,NS_Val_5> >::value=http://www.mamicode.com/=NS_Val_Min));
        Static_Assert((CGetEnumRangeMin<CEnumValue<SeqEnumRange,S_Val_3> >::value=http://www.mamicode.com/=S_Val_Min));
        Static_Assert((CGetEnumRangeMin<CEnumValue<SeqEnumRange,S_Val_5> >::value=http://www.mamicode.com/=S_Val_Min));


        //test UtilExt.CGetEnumValue 
        Static_Assert((CGetEnumValue<typename CEnumValue<NonSeqEnumRange,NS_Val_3>::Next<true>::type>::value=http://www.mamicode.com/=NS_Val_5));
        Static_Assert((CGetEnumValue<typename CEnumValue<SeqEnumRange,S_Val_3>::Next<true>::type>::value=http://www.mamicode.com/=S_Val_5)); //because SKIP_ENUM_ONE(SeqEnumRange,S_Val_4);


        //test UtilExt.CGetEnumType 
        Static_Assert((IsSameType<typename CGetEnumType<SEnumValueMin>::type,typename CGetEnumType<SEnumValueMax>::type>::value));
        Static_Assert((IsSameType<typename CGetEnumType<NSEnumValueMin>::type,typename CGetEnumType<NSEnumValueMax>::type>::value));
        Static_Assert((IsSameType<typename CGetEnumType<NonSeqEnumRange>::type,typename CGetEnumType<NSEnumValueMax>::type>::value));
        Static_Assert((IsSameType<typename CGetEnumType<NonSeqEnumRange>::type,typename CGetEnumType<NSEnumValueMin>::type>::value));
        Static_Assert(!(IsSameType<typename CGetEnumType<NSEnumValueMin>::type,typename CGetEnumType<SEnumValueMin>::type>::value));


        //test UtilExt.CEnumInRange 
        Static_Assert(!(CEnumInRange<typename NSEnumValueMin::Last<true>::type>::value));        
        Static_Assert((CEnumInRange<typename NSEnumValueMax::Last<true>::type>::value)); 
        Static_Assert((CEnumInRange<typename NSEnumValueMin::Next<true>::type>::value));        
        Static_Assert(!(CEnumInRange<typename NSEnumValueMax::Next<true>::type>::value));
        Static_Assert((CEnumInRange<typename NSEnumValueMin::Last<false>::type>::value));        
        Static_Assert(!(CEnumInRange<typename NSEnumValueMax::Last<false>::type>::value)); 
        Static_Assert(!(CEnumInRange<typename NSEnumValueMin::Next<false>::type>::value));        
        Static_Assert((CEnumInRange<typename NSEnumValueMax::Next<false>::type>::value)); 


        CNonSeqEunmInterface_1 nsCallObj_1(rand()%NS_Val_Max);
        CNonSeqEunmInterface_2 nsCallObj_2(TXT("I am CEnumInterface_2 :"));
        CSeqEunmInterface_1 sCallObj_1(rand()%S_Val_Max);
        CSeqEunmInterface_2 sCallObj_2(TXT("I am CSeqEunmInterface_2 :"));


        CTestEnumSuite testObj;
        testObj.testEntry();


        //test UtilExt.CTraverseEnum.apply
        ASSERT_AND_LOG((CTraverseEnum<NonSeqEnumRange,true>::apply(NS_Val_5,Template_Mem_Callback_Obj(CNonSeqEunmInterface_1,NonSeqEunm,apply),makeParamPackage(nsCallObj_1))));                    //test OK case
        ASSERT_AND_LOG((CTraverseEnum<NonSeqEnumRange,false>::apply(NS_Val_5,Template_Mem_Callback_Obj(CNonSeqEunmInterface_1,NonSeqEunm,apply),makeParamPackage(nsCallObj_1))));                   //test OK case
        ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,true>::apply(S_Val_5,Template_Mem_Callback_Obj(CSeqEunmInterface_1,SeqEunm,apply),makeParamPackage(sCallObj_1))));                               //test OK case
        ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,false>::apply(S_Val_5,Template_Mem_Callback_Obj(CSeqEunmInterface_1,SeqEunm,apply),makeParamPackage(sCallObj_1))));                              //test OK case


        //test UtilExt.CTraverseEnum.applyFrom 
        ASSERT_AND_LOG((CTraverseEnum<NonSeqEnumRange,true>::applyFrom<NS_Val_1>(NS_Val_3,Template_Mem_Callback_Obj(CNonSeqEunmInterface_2,NonSeqEunm,apply),makeParamPackage(nsCallObj_2))));      //test OK case
        ASSERT_AND_LOG((CTraverseEnum<NonSeqEnumRange,false>::applyFrom<NS_Val_5>(NS_Val_3,Template_Mem_Callback_Obj(CNonSeqEunmInterface_2,NonSeqEunm,apply),makeParamPackage(nsCallObj_2))));     //test OK case
        ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,true>::applyFrom<S_Val_1>(S_Val_3,Template_Mem_Callback_Obj(CSeqEunmInterface_2,SeqEunm,apply),makeParamPackage(sCallObj_2))));                  //test OK case
        ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,false>::applyFrom<S_Val_5>(S_Val_3,Template_Mem_Callback_Obj(CSeqEunmInterface_2,SeqEunm,apply),makeParamPackage(sCallObj_2))));                 //test OK case


        #if defined(_MSC_VER) && (WINVER >= 0x0500)
            #pragma push_macro("_Assert_Trigger")
            #pragma push_macro("ChkExceptionThrow")
                #undef _Assert_Trigger
                #define _Assert_Trigger()
                #undef ChkExceptionThrow
                #define ChkExceptionThrow()
        #endif //end defined(_MSC_VER)


        ASSERT_AND_LOG((CTraverseEnum<NonSeqEnumRange,true>::apply(NonSeqEunm(NS_Val_Max+2),Template_Mem_Callback_Obj(CNonSeqEunmInterface_1 ,NonSeqEunm,apply),makeParamPackage(nsCallObj_1))));   //test Failure case because DemoEunm(NS_Val_Max+2) is not in range
        ASSERT_AND_LOG((CTraverseEnum<NonSeqEnumRange,false>::apply(NonSeqEunm(NS_Val_Min-2),Template_Mem_Callback_Obj(CNonSeqEunmInterface_1 ,NonSeqEunm,apply),makeParamPackage(nsCallObj_1))));  //test Failure case because DemoEunm(NS_Val_Min-2) is not in range
        ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,true>::apply(SeqEunm(S_Val_Max+2),Template_Mem_Callback_Obj(CSeqEunmInterface_1,SeqEunm,apply),makeParamPackage(sCallObj_1))));                  //test Failure case because DemoEunm(S_Val_Max+2) is not in range
        ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,false>::apply(SeqEunm(S_Val_Min-2),Template_Mem_Callback_Obj(CSeqEunmInterface_1,SeqEunm,apply),makeParamPackage(sCallObj_1))));                 //test Failure case because DemoEunm(S_Val_Min-2) is not in range


        ASSERT_AND_LOG((CTraverseEnum<NonSeqEnumRange,true>::applyFrom<NS_Val_5>(NS_Val_3,Template_Mem_Callback_Obj(CNonSeqEunmInterface_2,NonSeqEunm,apply),makeParamPackage(nsCallObj_2))));      //test Failure case because traverse from NS_Val_5. (NS_Val_3 < NS_Val_5)
        ASSERT_AND_LOG((CTraverseEnum<NonSeqEnumRange,false>::applyFrom<NS_Val_1>(NS_Val_3,Template_Mem_Callback_Obj(CNonSeqEunmInterface_2,NonSeqEunm,apply),makeParamPackage(nsCallObj_2))));     //test Failure case because reversed traverse from NS_Val_1. (NS_Val_1 < NS_Val_3)
        ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,true>::applyFrom<S_Val_5>(S_Val_3,Template_Mem_Callback_Obj(CSeqEunmInterface_2,SeqEunm,apply),makeParamPackage(sCallObj_2))));                  //test Failure case because traverse from S_Val_5. (S_Val_3 < S_Val_5)
        ASSERT_AND_LOG((CTraverseEnum<SeqEnumRange,false>::applyFrom<S_Val_1>(S_Val_3,Template_Mem_Callback_Obj(CSeqEunmInterface_2,SeqEunm,apply),makeParamPackage(sCallObj_2))));                 //test Failure case because reversed traverse from S_Val_1. (S_Val_1 < S_Val_3)


        #if defined(_MSC_VER) && (WINVER >= 0x0500)
            #pragma pop_macro("_Assert_Trigger")
            #pragma pop_macro("ChkExceptionThrow")
        #endif //end defined(_MSC_VER)
    }


#ifdef RUN_EXAMPLE_TRAVERSEENUM
    InitRunFunc(showUsage_traverseEnum);
#endif  //RUN_EXAMPLE_TRAVERSEENUM
}


#endif // COMPILE_EXAMPLE_TRAVERSEENUM


#endif // __test_TRAVERSEENUM_h_

15) .实现可变参数的(成员/非成员)模板函数的回调,消除类似代码