我正在创建Node
的通用集合。每个Node
具有Start
和End
类型。并且一个的End
类型必须与下一个的Start
类型匹配。
如果我要列出集合中的每种类型,则构造函数将如下所示(对于四种类型):
template <typename Start, typename End>
class Node {
};
template <typename A, typename B, typename C, typename D>
class Collection
{
public:
Collection(Node<A, B> n1, Node<B, C> n2, Node<C, D> n3) { }
};
但是,当我尝试将构造函数编写为可变参数模板以支持任意数量的类型时,我感到很困惑。
最佳答案
我提出了一些不同的解决方案。
给定一个琐碎的tag
结构来包装泛型类型(以避免在std::tuples
中无法默认构造的类型的问题)
template <typename>
struct tag
{ };
以及一个基于
std::tuple
定义2种类型的辅助结构template <typename...>
struct getTpls;
template <std::size_t ... Is, typename ... Ts>
struct getTpls<std::index_sequence<Is...>, Ts...>
{
using tpl0 = std::tuple<tag<Ts>...>;
using ftpl = std::tuple<std::tuple_element_t<Is, tpl0>...>;
using stpl = std::tuple<std::tuple_element_t<1u+Is, tpl0>...>;
};
你可以这样写
Collection
template <typename ... Ts>
struct Collection
{
static_assert( sizeof...(Ts) > 1u, "more types, please");
using getT = getTpls<std::make_index_sequence<sizeof...(Ts)-1u>, Ts...>;
using ftpl = typename getT::ftpl;
using stpl = typename getT::stpl;
template <typename ... FTs, typename ... STs,
std::enable_if_t<
std::is_same_v<ftpl, std::tuple<tag<FTs>...>>
&& std::is_same_v<stpl, std::tuple<tag<STs>...>>, int> = 0>
Collection (Node<FTs, STs> ...)
{ }
};
以下是完整的编译示例
#include <tuple>
#include <type_traits>
template <typename Start, typename End>
class Node
{ };
struct A {};
struct B {};
struct C {};
template <typename>
struct tag
{ };
template <typename...>
struct getTpls;
template <std::size_t ... Is, typename ... Ts>
struct getTpls<std::index_sequence<Is...>, Ts...>
{
using tpl0 = std::tuple<tag<Ts>...>;
using ftpl = std::tuple<std::tuple_element_t<Is, tpl0>...>;
using stpl = std::tuple<std::tuple_element_t<1u+Is, tpl0>...>;
};
template <typename ... Ts>
struct Collection
{
static_assert( sizeof...(Ts) > 1u, "more types, please");
using getT = getTpls<std::make_index_sequence<sizeof...(Ts)-1u>, Ts...>;
using ftpl = typename getT::ftpl;
using stpl = typename getT::stpl;
template <typename ... FTs, typename ... STs,
std::enable_if_t<
std::is_same_v<ftpl, std::tuple<tag<FTs>...>>
&& std::is_same_v<stpl, std::tuple<tag<STs>...>>, int> = 0>
Collection (Node<FTs, STs> ...)
{ }
};
int main ()
{
Collection<A, B, C> c0{Node<A, B>{}, Node<B, C>{}}; // compile
// Collection<A, B, B> c1{Node<A, B>{}, Node<B, C>{}}; // error!
}
关于c++ - 按对展开可变参数模板包,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56367136/