且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在现代C ++中基于另一组可变参数模板参数表示可变参数模板类型?

更新时间: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 an Example with template parameters bool, int, char, double.
7ExampleIJdiiiEE as second line, means an Example with template parameters double (mapped from the bool) and 3 int (the default mapping).