反向层次结构中的可变参数模板参数

Reverse variadic template arguments in hierarchy

本文关键字:参数 变参 层次结构      更新时间:2023-10-16

我目前有这个使用typelist的类:

template<class AbstractF, template<class, class > class Creator, class TList>
class A: public B<typename Reverse<TList>::Result, Creator, AbstractF> {
};

我正在尝试使代码对 c++11 更加友好,用可变参数模板参数替换类型列表。

template<class AbstractF, template<class, class > class Creator, class TList...>
class A: public B<Creator, AbstractF, TList...> { //<---how to reverse here?
};

问题是:如何反转可变参数列表?查看其他问题,我看到了std::tuple的使用,但在这种情况下,我无法理解如何"解压缩"它,因为可变参数不是简单模板化函数的一部分,但它们用作类层次结构中的参数。

如果包中的所有类型都是不同的,则可以根据类型本身计算类型的index。剩下的就是从包装中提取N - 1 - index类型:

template<std::size_t index, class... Ts>
using Nth_type = std::tuple_element_t<index, std::tuple<Ts...>>;
template<class S, class... Ts>
inline constexpr std::size_t type_index = 0;
template<class S, class T, class... Ts>
inline constexpr std::size_t type_index<S, T, Ts...> = 
std::is_same_v<S, T> ? 0 : 1 + type_index<S, Ts...>;
template<class T, class... Ts>
using Reverser = Nth_type<sizeof...(Ts) - 1 - type_index<T, Ts...>, Ts...>;

简单的例子:

template<class... Ts>
class B;
template<class... Ts>
using RB = B<Reverser<Ts, Ts...>...>;   // two pack expansions here
static_assert(std::is_same<RB<>, B<>>());
static_assert(std::is_same<RB<int>, B<int>>());
static_assert(std::is_same<RB<int, float, double>, B<double, float, int>>());

如果允许包包含相同的类型,则此技巧将不起作用。

此代码使用一些 C++14/17 功能。变量模板不是 C++11 的一部分,因此type_index必须以不同的方式实现。这是一个可能的实现。

我正在尝试使代码对 c++11 更友好 用可变参数模板参数替换类型列表

如果您使用旧的类型列表方式(类型的链接列表( 然后在 C++11 中,您甚至可以使用解压缩的可变参数模板参数,或者在std::tuple或类似中使用打包的可变参数模板参数。

解包方式在操作(转换、跳过头、串联(方面有限制,可能需要先使用打包方式。

对于重新排序,包装方式可能是:

template <typename TypeList, typename Seq> struct ReverseImpl;
template <typename TypeList, std::size_t ... Is>
struct ReverseImpl<TypeList, std::index_sequence<Is...>>
{
using type = std::tuple<typename std::tuple_element<sizeof...(Is) - 1 - Is, TypeList>::type...>;
};

template <typename TypeList> struct Reverse
{
using Result =
typename ReverseImpl<TypeList,
std::make_index_sequence<std::tuple_size<TypeList>::value>>::type;
};

注意:std::index_sequence/std::make_index_sequence是C++14,但可以在C++11中实现。

可能的用法可能是:

template <template<class, class > class Creator, class AbstractF, typename TypeList>
struct BUnpack;
template<template<class, class > class Creator, class AbstractF, typename ... Ts>
class BUnpack<Creator, AbstractF, std::tuple<Ts...>>
{
using type = B<Creator, AbstractF, Ts...>;
};
template<class AbstractF, template<class, class > class Creator, typename ... Ts>
class A: public BUnpack<Creator, AbstractF, typename Reverse<std::tuple<Ts...>>::Result>::type {
};