第二個壞是因爲很多原因。
首先,稱它是一團糟。模板內部的模板需要使用template
關鍵字。其次,它要求你的類型列表包含你想要在其正文中的類型列表上進行的每個操作。就像將一個string
上的每個操作定義爲字符串上的方法一樣:如果允許使用免費函數,則可以創建新操作,甚至可以實現覆蓋。
最後,考慮隱藏::type
:
開始與這些原語:
template<class T>struct tag{using type=T;};
template<class Tag>using type_t=typename Tag::type;
template<class...Ts>struct types : tag<types<Ts...>>{};
變換,或fmap
,那麼看起來像:
template<template<class...>class Z, class Types>
struct fmap;
template<template<class...>class Z, class...Ts>
struct fmap<Z, types<Ts...>>:types<Z<Ts...>>{};
template<template<class...>class Z, class Types>
using fmap_t = type_t<fmap<Z,Types>>;
,你既可以使用type_t<fmap<Z,types<int,double>>>
,或fmap_t<Z,types<int,double>>
獲取映射類型的類型。
另一種方法是使用含有各種事情constexpr
功能:
template<class T>struct tag{using type=T;};
template<class...>struct types{using type=types;};
template<class Tag>using type_t=typename Tag::type;
template<template<class...>class Z>
struct z {template<class...Ts>using apply=Z<Ts...>; constexpr z(){};};
template<class...Ts>
struct one_type {};
template<class T0>
struct one_type<T0> { using type=T0; };
template<class...Ts>
using one_type_t=typename one_type<Ts...>::type;
template<template<class>class Z>
struct z_one_base {
template<class...Ts>
using helper = Z<one_type_t<Ts...>>;
using type = z<helper>;
};
template<template<class>class Z>
using z_one = type_t<z_one_base<Z>>;
現在fmap
很簡單:
// take a template metafunction and a list of types
// and apply the metafunction to each type, returning the list
template<template<class...>class Z, class...Ts>
constexpr auto fmap(z<Z>, types<Ts...>)
-> types<Z<Ts>...> { return {}; }
等功能如下:
// a template metafunction and a list of types
// and apply the template metafunction to all of the types
template<template<class...>class Z, class...Ts>
constexpr auto apply(z<Z>, types<Ts...>)
-> tag<Z<Ts...>> { return {}; }
// take any number of tags
// and make a type list from them
template<class...Tags>
constexpr auto make_list(Tags...)
-> types<type_t<Tags>...> { return {}; }
// concat of nothing is an empty list
constexpr types<> concat() { return {}; }
// concat of a list alone is a list alone:
template<class...T1s>
constexpr auto concat(types<T1s...>)
->types<T1s...>{ return {}; }
// concat of 2 or more lists is the concat of the first two,
// concatted with the rest
template<class...T1s, class...T2s, class...Types>
constexpr auto concat(types<T1s...>,types<T2s...>,Types...)
->decltype(concat(types<T1s...,T2s...>{},Types{}...))
{ return {}; }
// take a tagged list or a tagged type, and return a list
template<class T>
constexpr auto fbox(tag<T>)->types<T> { return {}; }
template<class...Ts>
constexpr auto fbox(tag<types<Ts...>>)->types<Ts...> { return {}; }
// create z_ versions of functions above:
#define CAT2(A,B) A##B
#define CAT(A,B) CAT2(A,B)
// lift functions to metafunctions with z_ prefix:
#define Z_F(F) \
template<class...Ts> \
using CAT(meta_, F) = decltype(F(Ts{}...)); \
using CAT(CAT(z_, F),_t) = z<CAT(meta_, F)>; \
static constexpr CAT(CAT(z_, F),_t) CAT(z_, F){}
Z_F(concat);
//Z_F(apply);
//Z_F(fmap);
Z_F(fbox);
static constexpr z_one<tag> z_tag{};
// joins a list of lists or types into a list of types
template<class...Ts>
constexpr auto join1(types<Ts...>)
->type_t<decltype(apply(z_concat, fmap(z_fbox, types<tag<Ts>...>{})))>
{ return {}; }
template<class Types>
constexpr auto join(Types types)
->type_t<decltype(apply(z_concat, fmap(z_fbox, fmap(z_tag, types))))>
{ return {}; }
template<class Z, class...Ts>
constexpr auto fbind(Z z, Ts...ts)
->decltype(join(fmap(z, ts...)))
{ return {}; }
和工作與僞造類型(tag
s)而不是直接在頂層輸入類型。如果您需要在需要時回升至type_t
的類型。
我認爲這是一種boost::hana
的方法,但我只開始看boost::hana
。這樣做的好處是,我們將類型捆綁與操作分離,我們可以訪問完整的C++重載(而不是模板模式匹配,這可能會更脆弱),我們可以直接推導出類型捆綁包的內容,而無需做using
和空主要專門技巧。
所有消耗的東西都是包裝類型tag<?>
或types<?>
或z<?>
,所以沒有什麼是「真實的」。
測試代碼:
template<class T> using to_double = double;
template<class T> using to_doubles = types<double>;
int main() {
types< int, int, int > three_ints;
auto three_double = fmap(z_one<to_double>{}, three_ints);
three_double = types<double, double, double >{};
auto three_double2 = join(fmap(z_one<to_doubles>{}, three_ints));
three_double = three_double2;
auto three_double3 = fbind(z_one<to_doubles>{}, three_ints);
three_double3 = three_double2;
}
Live example。
它是'typename L :: template transform'與'transform '。 –
啊,嗯,沒有考慮調用代碼的醜陋。 –