還有存放成員函數地址的鏈表節點
struct MethodNode
{
MethodNode(MethodNode*& head, TestMethodPtr method)
{
mNext = head;
head = this;
mMethod = method;
}
MethodNode* mNext;
TestMethodPtr mMethod;
};
還有提取成員函數地址的函數
template <class OutputClass, class InputClass>
union horrible_union{
OutputClass out;
InputClass in;
};
template <class OutputClass, class InputClass>
inline void union_cast(OutputClass& out, const InputClass input){
horrible_union<OutputClass, InputClass> u;
static_assert(sizeof(InputClass) == sizeof(u) && sizeof(InputClass) == sizeof(OutputClass), "out and in should be the same size");
u.in = input;
out = u.out;
}
template<typename Ty>
TestMethodPtr GetTestMethod(void(Ty::*testMethod)())
{
TestMethodPtr methodPtr;
union_cast(methodPtr, testMethod);
return methodPtr;
}
方法是每定義一個測試函數,在其上面就先定義一個鏈表節點變量,其構造函數記錄測試函數地址,并把自身加入到鏈表中。但是,在此之前,我們將遭遇到編譯器的抵觸。比如
struct TestCase
{
typedef TestCase ThisType;
MethodNode* mMethods = nullptr;
TestMethodPtr mTestMethodfn1 = GetTestMethod(&fn1);
void fn1(){}
};
vc下面,編譯器報錯 error C2276: “&”: 綁定成員函數表達式上的非法操作
原來在就地初始化的時候,不能以這種方式獲取到地址。然后,試試在TestCase里面的其他函數中,包括靜態函數,就可以將取地址符號用到成員函數前面。
這好像分明是編譯器在故意刁難,不過,任何代碼上的問題都可以通過引入中間層來予以解決。用內部類。
struct TestCase
{
typedef TestCase ThisType;
MethodNode* mMethods = nullptr;
struct Innerfn1 : public MethodNode
{
Innerfn1(ThisType* pThis) : MethodNode(pThis->mMethods, GetTestMethod(&ThisType::fn1))
{
}
} mTestMethodfn1 = this;
void fn1(){}
struct Innerfn2 : public MethodNode
{
Innerfn2(ThisType* pThis) : MethodNode(pThis->mMethods, GetTestMethod(&ThisType::fn2))
{
}
} mTestMethodfn2 = this;
void fn2(){}
};
有多少個測試方法,就動用多少種內部類。然后,一旦定義一個測試類的變量,那么這些內部類的構造函數就執行了,把測試方法串聯在一塊,逆序,也就是說最后定義測試方法反而跑到前面去了。這樣子就自動記錄下來所有的測試方法的地址。有了這些函數地址信息,后面怎么玩都可以。包括漂亮的測試結果顯示,日志記錄,甚至嵌入到vs的單元測試界面中,又或者是生成配置文件,各種花招,怎么方便就怎么玩。這個時候,可以拿來主義,把cppunit,gtest等的優點都吸收過來。
是否覺得這還不夠,好像有很多事情要做。比如說,測試方法逆序了,在同一個測試類的變量上執行這些測試方法,會不會就擾亂類的內部信息了,每次new一個測試類,所有的測試方法都要重復記錄,內部類變量要占內存……。咳咳,這些都可以一一解決。這里只是用最簡明的方式展示自動記錄測試方法,產品級的寫法肯定大有講究了。
可以看到上面的代碼都是有意做成很相似的,這些都是準備給宏大展身手的。這些低級宏太容易編寫了,任何經歷mfc或者boost代碼折磨的猿猴,都完全能夠勝任,這就打住了。對了,這里的自動記錄成員函數的宏手法,可以大量地使用到其他地方,比如說,自動生成消息映射表,比mfc的那一套要好一百倍,應用范圍太廣了。當初老朽以為就只能用于單元測試框架的編寫上面,想不到其威力如此巨大,消息系統全靠它了。C++的每一項奇技淫巧和功能被發現后,其價值都難以估量,好像bs所說的,他老人家不會給c++增添一項特性,其應用范圍一早就可以預料的。對付一個問題,C++有一百種解決方案,當然里面只有幾種才最貼切問題領域,但是很多時候,我們往往只選擇或者尋找到另外的那90多種,最后注定要悲劇。