在做模板元编程,IMO它总是有助于保持“元部分”和“非元部分”尽可能分开。这样,您可以首先考虑“元部分”,就好像它是一个正常的程序一样,使用类型而不是数值。所以一个模板变成一个函数,将某些类型(或者“高阶编程”:其他模板)作为输入并返回一些类型(或者对于“高阶编程”:其他模板)。
因此,首先退一步,不要考虑模板,元编程等等。你有一个清单S
。对于S
的每个项目,您想要调用某个函数,并组合返回项目的列表。所以你需要一个函数,给定列表中的一个项目,返回它映射到的项目。我们称之为mapping
。您还需要一个功能,将所述功能应用并将其应用于您的列表,即对每个项目调用mapping
并组装结果列表。我们称之为map
。
现在变成一个元程序:
// mapping :: TYPE -> TYPE
// ---------------------------------------------------------
// ?? --> int (default "value")
template<typename X> struct mapping {
using type = int;
};
// if instead you want it to be undefined for unknown types:
//template<typename X> struct mapping;
// bool --> double
template<> struct mapping<bool> {
using type = double;
};
现在map
,广义使得它可以使用像mapping
东西:
// map :: ([T] -> T) -> (T -> T) -> ([T] -> T)
// "List" "Mapping" result "type" (also a "List")
// --------------------------------------------------------
template<template<typename...> class List,
template<typename> class Mapping>
struct map {
template<typename... Elements>
using type = List<typename Mapping<Elements>::type...>;
};
最后,适用于您的Example
(这是一种因为它“拥有”多种类型)和具体mapping
:
template<typename... S>
using MappedExample = map<Example, mapping>::type<S...>;
现在你已经得到了产生的模板,在非元程序使用它:
template<typename... S>
MappedExample<S...> f() {
return MappedExample<S...>{};
}
Live example:
int main() {
std::cout
<< typeid(Example<bool,int,char,double>).name()
<< std::endl
<< typeid(decltype(f<bool, int, char, double>())).name()
<< std::endl;
}
输出:
在第一线7ExampleIJbicdEE
意指具有模板参数的Example
b ool,i nt,c har,d ouble。
如第二行中,是指具有一个模板参数Example
d ouble(来自布尔映射)和3 我 NT(默认映射)。
那么,对于哪种语言版本呢?你通常应该只指定一个。 – tambre
@tambre,C++ 17很好。 – HanXu