完整的源代码及用法测试代码可以在我的资源中去下载.
C++语法不支持模板函数/模板成员函数作为回调函数,同时把运行期代码向编译期代码转换也只有switch...case或者if..else能够实现。
如果case比较多的时候,代码非常臃肿,而且类似的大片代码中,往往只有一个参数的不同,其它都是相同的。这对于用户来说,都是一个大量的重复性的hard-code性的负担,而且也容易导致出错。
本库采用了封装,可以把运行性的switch...case/if..else分支选择转换为编译期的代码,支持模板函数的回调,并且支持最多6个可变参数(可以简易扩充参数个数),从而可以大幅度地减少代码量,(代码量可以减少到原代码的1/N,N为case数目)。并且由于是编译期代码,从而保证不会出错(出错将导致编译失败)。
并且附带提供了CEnumRange,可以检测一个枚举值是否在枚举范围内。
namespace UnitTest
{
template
bool globalEnumFunc(int a,char* pStr)
{
printf("globalEnumFunc [%d],param=%d,%s",TVal+1,a,pStr?pStr:"NULL");
return true;
}
Declare_Template_Global_CallBack(globalEnumFunc,globalEnumFunc);
struct CNonSeqEunmInterface_1
{
CNonSeqEunmInterface_1(int p) : m_bResult(false),m_param(p){};
template
void execute()
{
dbgOutput(TXT("\n\n[NonSeqEunm]Enum value is %d."),TVal);
dbgOutput(TXT("\n[CEnumInterface_1::execute] %d\n"),TVal);
m_bResult = (TVal+m_param) > NS_Val_Max;
}
bool m_bResult;
int m_param;
};
Declare_Template_Global_CallBack(CNonSeqEunmInterface_1,::UnitTest::CNonSeqEunmInterface_1::execute);
struct CNonSeqEunmInterface_2
{
CNonSeqEunmInterface_2(VCHAR* pStr) : m_bResult(false),m_pStr(pStr){};
template
void execute()
{
dbgOutput(TXT("\n\n[NonSeqEunm]Enum value is %d."),TVal);
dbgOutput(TXT("\n[CEnumInterface_2::execute] %s %d\n"),m_pStr,TVal);
m_bResult = (TVal+2) > NS_Val_Max;
}
bool m_bResult;
VCHAR* m_pStr;
};
Declare_Template_Global_CallBack(CNonSeqEunmInterface_2,::UnitTest::CNonSeqEunmInterface_2::execute);
struct CSeqEunmInterface_1
{
CSeqEunmInterface_1(int p) : m_bResult(false),m_param(p){};
template
void execute()
{
dbgOutput(TXT("\n\n[SeqEunm]Enum value is %d."),TVal);
dbgOutput(TXT("\n[CSeqEunmInterface_1::execute] %d\n"),TVal);
m_bResult = (TVal+m_param) > NS_Val_Max;
}
bool m_bResult;
int m_param;
};
Declare_Template_Global_CallBack(CSeqEunmInterface_1,::UnitTest::CSeqEunmInterface_1::execute);
struct CSeqEunmInterface_2
{
CSeqEunmInterface_2(VCHAR* pStr) : m_bResult(false),m_pStr(pStr){};
template
void execute()
{
dbgOutput(TXT("\n\n[SeqEunm]Enum value is %d."),TVal);
dbgOutput(TXT("\n[CSeqEunmInterface_2::execute] %s %d\n"),m_pStr,TVal);
m_bResult = (TVal+2) > NS_Val_Max;
}
bool m_bResult;
VCHAR* m_pStr;
};
Declare_Template_Global_CallBack(CSeqEunmInterface_2,::UnitTest::CSeqEunmInterface_2::execute);
class CTestEnumSuite
{
public:
template
bool printEnum()
{
outputTxt((TXT("CTestEnumSuite::printEnum [%d]\n"),TVal));
return true;
}
template
bool printNext()
{
outputTxt((TXT("CTestEnumSuite::printNext [%d]\n"),TVal+1));
return true;
}
template
void inOutParam(char p1,int& outParam)
{
outputTxt((TXT("CTestEnumSuite::inOutParam [%d]\n"),TVal+1));
outParam = p1+2;
}
template
int getReturnValue(char p1,int outParam)
{
outputTxt((TXT("CTestEnumSuite::inOutParam [%d]\n"),TVal+1));
return outParam+p1+TVal+4;
}
template
bool print2Param(int a,char* pStr)
{
printf("CTestEnumSuite::print2Param [%d],param=%d,%s\n",TVal+1,a,pStr?pStr:"NULL");
return true;
}
Declare_Template_Global_CallBack(printEnum,::UnitTest::CTestEnumSuite::printEnum );
Declare_Template_Global_CallBack(printNext,::UnitTest::CTestEnumSuite::printNext );
Declare_Template_Global_CallBack(print2Param,::UnitTest::CTestEnumSuite::print2Param );
Declare_Template_Global_CallBack(inOutParam,::UnitTest::CTestEnumSuite::inOutParam );
Declare_Template_Global_CallBack(getReturnValue,::UnitTest::CTestEnumSuite::getReturnValue );
void testEntry()
{
int a = 5;
char* pStr = "in testEntry";
srand( (unsigned)time( NULL ) );
typedef CTraverseTypeSet
typedef CTraverseTypeSet
typedef CTraverseTypeSet
typedef CTraverseTypeSet
//test member function
typedef bool (CTestEnumSuite::*pNoParam)();
typedef bool (CTestEnumSuite::*pMemParam2)(int,char*);
ASSERT_AND_LOG((NonSeqEnumRange0::applyTester<>::execute
ASSERT_AND_LOG((NonSeqEnumRange1::applyTester<>::execute
ASSERT_AND_LOG((SeqEnumRange0::applyTester<>::execute
ParmPackage
ASSERT_AND_LOG((SeqEnumRange1::applyTester<>::execute
//test foreach
SeqEnumRange1::forEach
//test in-out parameter
char p1 = 3;
int outP = 6;
typedef void (CTestEnumSuite::*pParam2ci)(char,int&);
ParmPackage
ASSERT_AND_LOG((SeqEnumRange0::applyTester<>::execute
ASSERT_AND_LOG((p1+2)==outP);
ASSERT_AND_LOG(SeqEnumRange1::applyTester<>::execute
ASSERT_AND_LOG((p1+2)==outP);
typedef int (CTestEnumSuite::*pGetRetVal)(char,int);
ASSERT_AND_LOG((p1+outP+S_Val_5+4)==SeqEnumRange1::applyTester<>::execute
pGetRetVal pf=SeqEnumRange1::applyTester<>::getFuncAddr
ASSERT_AND_LOG(pf);
pf=SeqEnumRange1::applyTester<>::getFuncAddr
ASSERT_AND_LOG(!pf); //S_Val_4 is skipped
stlMap
ASSERT_AND_LOG((NonSeqEnumRange0::applyFuncIdGenerator<>::getAllFuncAddr
ASSERT_AND_LOG(CGetEnumRangeSize
stlMap
ASSERT_AND_LOG((NonSeqEnumRange1::applyFuncIdGenerator<>::getAllFuncAddr
ASSERT_AND_LOG(rMap10 ==rMap11 );
stlMap
ASSERT_AND_LOG((SeqEnumRange0::applyFuncIdGenerator<>::getAllFuncAddr
stlMap
ASSERT_AND_LOG((SeqEnumRange1::applyFuncIdGenerator<>::getAllFuncAddr
ASSERT_AND_LOG(rMap20 ==rMap21 );
stlMap
ASSERT_AND_LOG((SeqEnumRange1::applyFuncIdGenerator<>::getAllFuncAddr
ASSERT_AND_LOG(rMap20 ==rMap21New );
ASSERT_AND_LOG((NonSeqEnumRange0::applyTester<>::execute
ASSERT_AND_LOG((NonSeqEnumRange1::applyTester<>::execute
//test global function
typedef bool (*pGlobalParam2)(int,char*);
ParmPackage
ASSERT_AND_LOG((SeqEnumRange0::applyTester<>::execute
ASSERT_AND_LOG((SeqEnumRange1::applyTester<>::execute
ASSERT_AND_LOG(!(SeqEnumRange0::applyTester<>::execute
}
};
//
inline void TestCase_traverseTypeSet()
{
PrintTestcase();
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();
typedef CTraverseTypeSet
typedef CTraverseTypeSet
typedef CTraverseTypeSet
typedef CTraverseTypeSet
outputTxt(( SeqEnumRange0::dump().c_str() ));
outputTxt(( SeqEnumRange1::dump().c_str() ));
outputTxt(( NonSeqEnumRange0::dump().c_str() ));
outputTxt(( NonSeqEnumRange1::dump().c_str() ));
outputTxt(( CTraverseTypeSet
outputTxt(( CTraverseTypeSet
//test MiniMPL.CTraverseEnum.execute
typedef void (CNonSeqEunmInterface_1::*pNoParamN11)();
typedef void (CSeqEunmInterface_1::*pNoParamS11)();
pNoParamS11 pf = SeqEnumRange1::applyTester<>::getFuncAddr
ASSERT_AND_LOG( &CSeqEunmInterface_1::execute
ASSERT_AND_LOG( &CSeqEunmInterface_1::execute
ASSERT_AND_LOG((NonSeqEnumRange1::applyTester<>::execute
ASSERT_AND_LOG((NonSeqEnumRange0::applyTester<>::execute
ASSERT_AND_LOG((SeqEnumRange1::applyTester<>::execute
ASSERT_AND_LOG((SeqEnumRange0::applyTester<>::execute
//test MiniMPL.CTraverseEnum.executeFrom
typedef void (CNonSeqEunmInterface_2::*pNoParamN21)();
typedef void (CSeqEunmInterface_2::*pNoParamS21)();
ASSERT_AND_LOG((NonSeqEnumRange1::applyTester<>::executeFrom
ASSERT_AND_LOG((NonSeqEnumRange0::applyTester<>::executeFrom
ASSERT_AND_LOG((SeqEnumRange1::applyTester<>::executeFrom
ASSERT_AND_LOG((SeqEnumRange0::applyTester<>::executeFrom
#if defined(_MSC_VER) && (WINVER >= 0x0500)
#pragma push_macro("Assert_Trigger")
#pragma push_macro("ChkExceptionThrow")
#undef Assert_Trigger
#define Assert_Trigger() 0
#undef ChkExceptionThrow
#define ChkExceptionThrow() 0
#endif //end defined(_MSC_VER)
ASSERT_AND_LOG((NonSeqEnumRange1::applyTester<>::execute
ASSERT_AND_LOG((NonSeqEnumRange0::applyTester<>::execute
ASSERT_AND_LOG((SeqEnumRange1::applyTester<>::execute
ASSERT_AND_LOG((SeqEnumRange0::applyTester<>::execute
ASSERT_AND_LOG((NonSeqEnumRange1::applyTester<>::executeFrom
ASSERT_AND_LOG((NonSeqEnumRange0::applyTester<>::executeFrom
ASSERT_AND_LOG((SeqEnumRange1::applyTester<>::executeFrom
ASSERT_AND_LOG((SeqEnumRange0::applyTester<>::executeFrom
#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_