我正在创建的通用集合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
s中不能默认构造的类型的问题)
template <typename>
struct tag
{ };
以及一个基于两个定义类型的辅助结构 std::tuple
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!
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句