首先解释这是如何工作的:
这是一个前向声明,因此我们可以将flatten 与单一类型一起使用。
template<class T>
struct flatten;
然后我们专门flatten 接受任何模板类型。
C 是一个模板模板参数,所以我们可以得到周围模板的类型。
例如。如果您将flatten 与参数std::tuple<int, double> 一起使用,那么C 将是std::tuple。
FArgs 用于检索传递的模板的参数列表。在我刚才提到的例子中,它是int, double
template< template< typename ... > class C, typename ...FArgs>
struct flatten<C<FArgs...>>
flatten 实现的其余部分现在始终可以访问 C 包装器类型和 FArgs 参数列表。
append 的转发声明,它将参数 B 附加到参数 Target 中的项目列表中
template< typename Target, typename B >
struct append;
append 的特化,它从Target 检索类型列表(见上文)。
请注意,这里的C 仍然是std::tuple。
因此,我们在列表中再添加一项,并通过应用先前的参数列表 Args1 然后添加 T 来创建新类型
template< typename ...Args1, typename T >
struct append<C<Args1...>, T> {
using type = C<Args1..., T>;
};
inner 和 inner2 的转发声明
inner 用于遍历提供的参数列表并在每个参数上应用inner2,如果类型是另一个带参数的模板,则反过来又在类型上应用inner。此模板必须是匹配的模板C
template< typename Target, typename ...Args >
struct inner;
template< typename Target, typename T >
struct inner2;
这个inner2 处理所有C 模板类型,并在inner 的帮助下递归遍历其参数列表
template< typename Target, typename ...Args>
struct inner2<Target, C<Args...>> {
using type = typename inner<Target, Args...>::type;
};
如果使用此 inner2 特化,则类型将附加到最终结果中。
template< typename Target, typename T >
struct inner2 {
using type = typename append<Target, T>::type;
};
通过继承和应用每个参数inner2来遍历模板参数
template< typename Target, typename T, typename ...Args>
struct inner<Target, T, Args...>
: inner<typename inner2<Target, T>::type, Args...>
{};
递归的结束条件。
template< typename Target, typename T >
struct inner<Target, T>
{
using type = typename inner2<Target, T>::type;
};
这里触发了上面的全部内容,C<> 指定了 Target 和 FArgs 是由 flatten 特化提取的参数。
using type = typename inner<C<>, FArgs...>::type;
};
这里是整个代码:
#include <tuple>
#include <string>
template<class T>
struct flatten;
template< template< typename ... > class C, typename ...FArgs>
struct flatten<C<FArgs...>>
{
template< typename Target, typename ...B >
struct append;
template< typename ...Args1, typename T >
struct append<C<Args1...>, T> {
using type = C<Args1..., T>;
};
template< typename Target, typename ...Args >
struct inner;
template< typename Target, typename T >
struct inner2;
template< typename Target, typename ...Args>
struct inner2<Target, C<Args...>> {
using type = typename inner<Target, Args...>::type;
};
template< typename Target, typename T >
struct inner2 {
using type = typename append<Target, T>::type;
};
template< typename Target, typename T, typename ...Args>
struct inner<Target, T, Args...>
: inner<typename inner2<Target, T>::type, Args...>
{};
template< typename Target, typename T >
struct inner<Target, T>
{
using type = typename inner2<Target, T>::type;
};
using type = typename inner<C<>, FArgs...>::type;
};
int main() {
typedef flatten<std::tuple<int, float, double>>::type first;
static_assert(std::is_same<first, std::tuple<int, float, double>>::value, "First not the same");
typedef flatten<std::tuple<int, std::tuple<float, double>>>::type second;
static_assert(std::is_same<second, std::tuple<int, float, double>>::value, "Second not the same");
typedef flatten<std::tuple<int, std::tuple<char const *>, std::tuple<std::tuple<float, int>, double>>>::type third;
static_assert(std::is_same<third, std::tuple<int, char const *, float, int, double>>::value, "Third not the same");
typedef flatten<std::tuple<int, std::tuple<std::tuple<std::tuple<std::tuple<char const *>>>>, std::tuple<std::tuple<float, int>, double>>>::type fourth;
static_assert(std::is_same<fourth, std::tuple<int, char const *, float, int, double>>::value, "Fourth not the same");
typedef flatten<std::tuple<int, std::tuple<std::tuple<std::tuple<std::tuple<std::string>>>>, std::tuple<std::tuple<float, int>, double>>>::type fifth;
static_assert(std::is_same<fifth, std::tuple<int, std::string, float, int, double>>::value, "Fifth not the same");
}
编辑:我重写了实现以使其更具可读性和更短(受@DyP 启发)
Edit2:解释代码