如何从 TypeList 重建参数包

How do I rebuild parameter pack from TypeList

我有一个可变模板类型列表:

template <class... Types>
struct typelist {};

那么我如何将它传递给一些需要参数包的外部代码,比如 std::tuple。换句话说,我需要将参数包作为成员或 typedef 存储在我的类型列表中,例如

...
struct typelist {
    using types = Types; // Imaginary syntax
}

然而这被编译器拒绝,说 Types is unexpanded。

任何解决方法?

此问题在中以另一种方式提到,但现有答案未涵盖。


评论中要求的详细信息:

如果我编译 (-std=c++17):

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

std::tuple<typelist<int, int>> tp{0,1};

g++ 给出 error: no matching function for call to ‘std::tuple<typelist<int, int> >::tuple(<brace-enclosed initializer list>)’ std::tuple<typelist<int, int>> tp{0,1};

如果我编译 (-std=c++17):

template <class... T>
struct typelist {
    using types = T;
};

g++ 给出 error: parameter packs not expanded with ‘...’: using types = T;

您不能在类型别名中存储参数包。您需要使用模板参数推导来提取 type_list 的参数以供重用。一种方法是使用像这样的虚拟函数:

template <typename... Args>
struct type_list {};

template <typename... Args>
std::tuple<Args...> to_tuple(type_list<Args...>);

template <typename TypeList>
struct type_list_to_tuple {
  using type = decltype(to_tuple(std::declval<TypeList>()));
};

template <typename TypeList>
using type_list_to_tuple_t = typename type_list_to_tuple<TypeList>::type;

int main() {
  using my_type_list = type_list<int, float>;
  using my_tuple = type_list_to_tuple_t<my_type_list>;
  static_assert(std::is_same_v<my_tuple, std::tuple<int, float>>);
}

您需要一些样板文件才能从 typelist 中获得正确的 tuple 专业化,因为您不能简单地按原样存储参数包。
例如,您可以通过正确使用函数声明和 using 声明来做到这一点:

#include<tuple>
#include<utility>
#include<type_traits>

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

template<typename... T>
std::tuple<T...> foo(typelist<T...>);

template<typename L>
using tupleFromTypelist = decltype(foo(std::declval<L>()));

int main() {
    using tl = typelist<int, int>;
    tupleFromTypelist<tl> tp{0,1};
    static_assert(std::is_same<tupleFromTypelist<tl>, std::tuple<int, int>>::value, "!");
}

或者像下面例子中的助手class:

#include<tuple>
#include<utility>
#include<type_traits>

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

template<typename>
struct helper;

template<typename... T>
struct helper<typelist<T...>> {
    using type = std::tuple<T...>;
};

int main() {
    using tl = typelist<int, int>;
    helper<tl>::type tp{0,1};
    static_assert(std::is_same<helper<tl>::type, std::tuple<int, int>>::value, "!");
}

否则,让typelist公开tuple特化并直接从中获取:

#include<tuple>
#include<utility>
#include<type_traits>

template <class... T>
struct typelist {
    using tuple = std::tuple<T...>;
};

int main() {
    using tl = typelist<int, int>;
    tl::tuple tp{0,1};
    static_assert(std::is_same<tl::tuple, std::tuple<int, int>>::value, "!");
}

如果它是您要为其使用参数包的唯一类型,这是最简单的方法。