下面我們實(shí)現(xiàn)一個(gè)能夠判斷兩個(gè)類型是否相等的元函數(shù):
template<typename T, typename U>
struct IsEqual
{
enum {Result = false};
};
template<typename T>
struct IsEqual<T, T>
{
enum {Result = true};
};
上面的實(shí)現(xiàn)中使用了模式特化,當(dāng)兩個(gè)類型相等時(shí),選擇特化版本,否則選擇非特化版本。
接下來(lái)我們實(shí)現(xiàn)一個(gè)在編譯期判斷兩個(gè)整數(shù)是否相等的元函數(shù):
template<int N, int M>
struct IsNumEqual
{
enum {Result = false};
};
template<int N>
struct IsNumEqual<N, N>
{
enum {Result = true};
};
我們看到,判斷整數(shù)是否相等的元函數(shù)的實(shí)現(xiàn)和前面對(duì)類型進(jìn)行判斷的元函數(shù)的實(shí)現(xiàn)完全一樣,唯獨(dú)入?yún)㈩愋筒煌S捎谠瘮?shù)不支持函數(shù)重載,所以必須得為這兩個(gè)元函數(shù)起不同的函數(shù)名稱。
另外,我們之前一直用Result表示返回類型,現(xiàn)在又用它返回?cái)?shù)值。這種返回型別上的差異,會(huì)讓我們?cè)诤瘮?shù)組合的時(shí)候碰到不少問題。
如果我們能有一個(gè)方法,讓所有的元函數(shù)的入?yún)⒌男蛣e和返回值型別都能一致化,那將對(duì)元函數(shù)的復(fù)用和組合帶來(lái)極大的好處。
有一個(gè)辦法可以讓我們把數(shù)值也變成一個(gè)類型。
// “tlp/int/IntType.h”
template<int V>
struct IntType
{
enum { Value = V };
using Result = IntType<V>;
};
有了IntType,我們可以讓每個(gè)整形數(shù)字都成為不同的類型,例如IntType<3>
和IntType<4>
就是不同的類型。雖然可以使用IntType<3>::Value
獲得它的數(shù)值,但在模板元編程中我們更傾向直接使用這種對(duì)數(shù)值封裝過后的類型,因?yàn)檫@樣可以讓模板元編程的計(jì)算對(duì)象統(tǒng)一成一種:只有類型!
同理,對(duì)于bool值,也如此封裝:
// “tlp/bool/BoolType.h”
template<bool V> struct BoolType;
template<>
struct BoolType<true>
{
enum { Value = true };
using Result = BoolType<true>;
};
template<>
struct BoolType<false>
{
enum { Value = false };
using Result = BoolType<false>;
};
using TrueType = BoolType<true>;
using FalseType = BoolType<false>;
用了該技術(shù),后續(xù)所有元函數(shù)的入?yún)⒑头祷刂刀贾幻嫦蝾愋停贈(zèng)]有數(shù)值。如此歸一化后,將會(huì)從根本上避免由于元編程的操作對(duì)象不一致造成的寫法上的重復(fù),進(jìn)一步讓元函數(shù)的組合能力變得更強(qiáng)。
得益于上述統(tǒng)一,IsEqual只需要如下一份實(shí)現(xiàn)就夠了:
// “tlp/bool/algo/IsEqual.h”
template<typename T, typename U>
struct IsEqual
{
using Result = FalseType;
};
template<typename T>
struct IsEqual<T, T>
{
using Result = TrueType;
};
前面我們實(shí)現(xiàn)過一個(gè)Print模板,用于在編譯過程中打印常量的值。現(xiàn)在一切都是類型,我們對(duì)Print的實(shí)現(xiàn)進(jìn)行修改,讓其可以在編譯期打印出類型結(jié)果的值。
// “tlp/test/details/Print.h”
template <typename T>
struct Print
{
const int Value = 1 / (sizeof(T) - sizeof(T));
};
#define __print(...) Print<__VA_ARGS__> UNIQUE_NAME(tlp_print_)
現(xiàn)在Print的入?yún)⒆優(yōu)橐粋€(gè)類型T,使用__print(T)
會(huì)產(chǎn)生一個(gè)編譯器的告警,在告警信息中輸出T的具體類型。__print()
在輸出前會(huì)先對(duì)其參數(shù)進(jìn)行求值。
// TestPrint.cpp
__print(IsEqual<IntType<5>, IntType<6>>::Result);
__print(IsEqual<TrueType, BoolType<true>>::Result);
上面的cpp文件在我的編譯環(huán)境下輸出的告警信息中包含如下內(nèi)容,其中攜帶著對(duì)__print()
的參數(shù)的求值結(jié)果。
TestPrint.cpp : in instantiation of default member initializer Print<BoolType<false> >::Value' required here
...
TestPrint.cpp : in instantiation of default member initializer Print<BoolType<true> >::Value' required here
可見IsEqual<IntType<5>, IntType<6>>::Result
的值是BoolType<false>
,而IsEqual<TrueType, BoolType<true>>::Result
的值是BoolType<true>
。
得益于我們將元編程的計(jì)算統(tǒng)一到類型上,我們得到了一個(gè)統(tǒng)一的Print元函數(shù)。