更新时间:2023-11-30 20:44:16
在进行模板元编程时,IMO始终有助于尽可能长时间地保持元部分和非元部分的分离。这样,您可以首先考虑元部分,就好像它是普通程序一样,对类型而不是值进行操作。因此,模板变成一个函数,以某种类型(或用于高阶编程:其他模板)作为输入并返回某种类型(或用于高阶编程:其他模板)。
When doing template meta programming, IMO it always helps to keep the "meta part" and the "non meta part" separate for as long as possible. That way you can first think about the "meta part" as if it were a normal program, operating on types instead of values. So a template becomes a function, taking some type(s) (or for "higher order programming": other templates) as input and returns some type (or for "higher order programming": other templates).
因此,首先,退后一步,不要考虑模板,元编程等。您有一个列表 S
。对于 S
的每个项目,您都想调用一些函数,并组合一个返回项目的列表。因此,您需要一个函数,该函数在给定列表的一个项目的情况下,返回它映射到的项目。我们将此函数称为 mapping
。您还需要一个具有上述功能并将其应用到列表的函数,即在每个项目上调用 mapping
并组合结果列表。我们称之为 map
。
So, first, step back for a second and don't think about templates, metaprogramming, and such. You have a list S
. For each item of S
, you want to call some function, and assemble a list of the returned items. So you need a function that, given one item of the list, returns the item it's mapped to. Let's call this function mapping
. You also need a function which takes said function and applies it to your list, i.e. calls the mapping
on each item and assembles the result list. Let's call that map
.
现在将其转换为元程序:
Now turn this into a meta program:
// 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
:
Now map
, generalized such that it can use anything like 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
(其中是一种列表,因为它持有多种类型)和具体的映射
:
Finally, apply to your Example
(which is kind of a list, because it "holds" multiple types) and the concrete mapping
:
template<typename... S>
using MappedExample = map<Example, mapping>::type<S...>;
现在您已经有了生成的模板,可以在非元程序中使用它:
Now you've got the resulting template, use it in your non-meta program:
template<typename... S>
MappedExample<S...> f() {
return MappedExample<S...>{};
}
实时示例:
int main() {
std::cout
<< typeid(Example<bool,int,char,double>).name()
<< std::endl
<< typeid(decltype(f<bool, int, char, double>())).name()
<< std::endl;
}
输出:
7ExampleIJbicdEE
在第一行中,表示具有模板参数 b的Example
ool, i nt, c har, d ouble。7ExampleIJdiiiEE
作为第二行,表示一个示例
,其模板参数为 d ouble(从布尔值映射),其中3个为 i nt(默认映射)。
7ExampleIJbicdEE
in the first line, means anExample
with template parameters bool, int, char, double.7ExampleIJdiiiEE
as second line, means anExample
with template parameters double (mapped from the bool) and 3 int (the default mapping).