2017-04-08 58 views
3

假设我有一个下面可变参数模板结构:如何基于现代C++中另一组可变参数模板参数来表示可变模板类型?

template <class... T> 
struct Example {}; 

现在我想定义模板功能:

template<class... S> 
??? f() { 
    return Example<???> 
} 

其中Example<>专业化是依赖于模板参数的fS

为了更加具体(而且简单),现在我只想返回Example<int, ...,int>,其中int的数量是参数包S的大小。

它如何在现代C++,即C++ 11/14/17中完成?

更一般地说,有没有办法在编译时定义模板参数上的函数?

+0

那么,对于哪种语言版本呢?你通常应该只指定一个。 – tambre

+0

@tambre,C++ 17很好。 – HanXu

回答

0

在做模板元编程,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意指具有模板参数的Exampleb ool,i nt,c har,d ouble。
如第二行中,是指具有一个模板参数Exampled ouble(来自布尔映射)和3 NT(默认映射)。

+0

优秀的方法!谢谢! – HanXu

4

您可以创建一个映射类型:

// Maps some type T to the type U. 
template <typename T, typename U> 
using Map = U; 

,您可以为使用如下:

template<class... S> 
Example<Map<S, int>...> f() { 
    return Example<Map<S, int>...>{}; 
} 
+0

请注意,只有在您想将所有类型映射到单个默认值时,才会使用这种“使用”。 (例如全部为“int”)。原因:你不能专门化它。 –

+0

聪明而酷!非常感谢!但的确如丹尼尔所说,这种方法只能用于相同的映射:) – HanXu