使用TypeList可以一次對一組類型進行操縱,關于如何應用它是一個非常有想象力的事情。例如我們可以用TypeList輕易地實現一個trait工具,用于判斷某一類型是否是C++內置類型:
// "tlp/traits/IsBuiltIn.h"
template<typename T>
struct IsBuiltIn
{
private:
using BuiltInTypes = __type_list(char, wchar_t, char16_t, char32_t, bool, short, int, long, long long, float, double, long double);
public:
using Result = __is_included(BuiltInTypes, T);
};
#define __is_built_in(...) typename IsBuiltIn<__VA_ARGS__>::Result
TEST("estimate a type whether a built in type")
{
struct Object {};
ASSERT_TRUE(__is_built_in(char));
ASSERT_FALSE(__is_built_in(Object));
};
下面我們再介紹一種使用TypeList完成類型創建的設計技巧,這種設計技巧可以被用于C++自動代碼生成,威力非常強大。
TLP中list的算法里有一個__scatter_inherits()
,它讓用戶傳入一個TypeList,以及一個模板template<typename> class Unit
。__scatter_inherits()
可以生成一個目標類,這個目標類繼承自每個TypeList的元素應用Unit后的類型。下面是一個例子:
template<typename T> struct Holder { T field; };
using Aggregator = __scatter_inherits(__type_list(int, short, char), Holder);
如上我們通過__scatter_inherits()
創建了類型Aggregator
,它多重繼承自Holder<int>
、Holder<short>
、Holder<char>
(見下面圖示)。
最終Aggregator
相當于有三個類型分別是int、short和char的成員變量。可以這樣調用它的成員變量:
Aggregator object;
object.Holder<int>::field = 5;
object.Holder<char>::field = 'a';
__scatter_inherits()
的實現如下:
// "tlp/list/algo/ScatterInherits.h"
template<typename TL, template<typename> class Unit> struct ScatterInherits;
template<template<typename> class Unit>
struct ScatterInherits<NullType, Unit>
{
};
template<typename Atom, template<typename> class Unit>
struct ScatterInherits : Unit<Atom>
{
};
template<typename Head, typename Tail, template<typename> class Unit>
struct ScatterInherits<TypeElem<Head, Tail>, Unit>
: ScatterInherits<Head, Unit>
, ScatterInherits<Tail, Unit>
{
};
#define __scatter_inherits(...) ScatterInherits<__VA_ARGS__>
__scatter_inherits()
的實現并不復雜,它采用多重繼承的方式,遞歸地繼承自Holder<T>
。
有時我們想控制讓這種繼承關系能夠保持單一繼承。于是TLP同時提供了__linear_inherits()
,它的參數和__scatter_inherits()
相同,差別是__linear_inherits()
創建的類型的繼承關系是一條單向繼承鏈。
下面的代碼示例中,我們創建了類型Aggregator
,它包含一組重載的成員方法void visit(const T& t)
。
template<typename T, typename Base>
struct Holder : Base
{
void visit(const T& t)
{
std::cout << t << std::endl;
};
};
using Aggregator = __linear_inherits(__type_list(int, short, char), Holder);
Aggregator object;
object.visit('a');
object.visit(-5);
上面代碼示例中使用了__linear_inherits()
,所以Aggregator的繼承關系圖是線性的。關于__linear_inherits()
的具體實現請參考“tlp/list/algo/LinearInherits.h”。
這兩個工具:__scatter_inherits()
和__linear_inherits()
都允許客戶通過一個TypeList和一個Unit模板來做類型生成,差別僅在于目標類型的繼承方式不同。它們的強大之處在于它們通過組合的手段來生成目標類型,而把組合元素以一個數據結構和算法的方式交給了客戶。