是否可以交错参数包?

时间:2016-06-22 19:17:28

标签: c++ templates c++11 variadic-templates

使用C ++ 11/14 / 1z,是否有可能使用带有两个参数包的模板化构造,并且在其中,实例化一些其他模板化构造,其中两个包是交错的?即,如果第一个包是T1_1,T1_2,T1_3,第二个包是T2_1,T2_2和T2_3,则交织包将是T1_1,T2_1,T1_2,T2_2,T1_3,T2_3?我的猜测是" no",因为省略号不应该适用于两个参数包元素指示符;但也许某种元组构造或递归实例化技巧可行吗?

编辑:让我明确假设包具有相同的长度(Node *aux,*prev; prev = *l; aux = prev->next; if(aux == NULL) { free(prev); *l = NULL; return; } 值)。对于不同长度的包装的解决方案将是不错的,只要它不会让事情变得更加复杂。

6 个答案:

答案 0 :(得分:2)

使用功能和decltype s,您可以轻松地执行此操作 这是一个有效的例子:

#include<tuple>

template<std::size_t... I>
constexpr auto f(std::index_sequence<I...>, auto tup1, auto tup2) {
    return std::tuple_cat(std::make_tuple(std::get<I>(tup1), std::get<I>(tup2))...);
}

template<typename... V>
struct S {
    template<typename... U, std::enable_if_t<(sizeof...(V) == sizeof...(U))>* = nullptr>
    static auto generate() {
        return f(std::make_index_sequence<sizeof...(U)>(), std::tuple<V...>{}, std::tuple<U...>{});
    }
};

int main() {
    static_assert(
        std::is_same<
            decltype(S<int, double>::template generate<char, void*>()),
            std::tuple<int, char, double, void*>
        >::value,
        "!"
    );
}

答案 1 :(得分:2)

使用document.getElementById("myfrndDetails").innerHTML = "lastname - " + frndLst[onefrnd].lastName + " and phoneNumber " + frndLst[onefrnd].phoneNumber ; 是过度的。更不用说不必要的约束了。

琐碎的包类:

tuple_cat

可变的连续,写得相当简单:

template<class...> struct pack {};

然后交错本身同样微不足道 - 扩展为两种类型的包,然后将它们连接起来:

template<class T = pack<>, class...> 
struct concat { using type = T; };

template<class... T1, class... T2, class... Ts>
struct concat<pack<T1...>, pack<T2...>, Ts...> 
    : concat<pack<T1..., T2...>, Ts...> {};

template<class... Ts> 
using concat_t = typename concat<Ts...>::type;

Demo

答案 2 :(得分:1)

实际上,所有单件都已添加到标准中。我现在无法自己测试,但这个想法应该有用。

template <class Tuple1, class Tuple2, std::size_t ... indices>
auto interleave(Tuple1 t1, Tuple2 t2, std::integer_sequence<std::size_t, indices...>)
{
    return std::tuple_cat(std::make_tuple(std::get<indices>(t1),
                                          std::get<indices>(t2))...);
}


template <class Tuple1, class Tuple2>
auto interleave(Tuple1 t1, Tuple2 t2)
{
    return interleave(t1, t2, std::make_index_sequence<std::tuple_size<Tuple1>::value>());
}

答案 3 :(得分:0)

当然可以。您可以通过包装器获得两个不同的包:

template < typename L0, typename L1 >
struct interleave;

template < typename ... Pack >
struct pack {};

template < typename ... P0, typename ... P1 >
struct interleave<pack<P0...>, pack<P1...>>
{
   using type = ???;
};

答案 4 :(得分:0)

#include <tuple>
#include <iostream>
#include <utility>
#include <typeinfo>

template<class T1, class T2>
struct interleave
{
  static constexpr std::size_t size = std::tuple_size<T1>::value;
  static_assert(size == std::tuple_size<T2>::value, ""); 

  template<class T> struct impl;

  template<std::size_t...Is>
  struct impl<std::index_sequence<Is...>>
  {
    using type = std::tuple
      <
      std::tuple<std::tuple_element_t<Is, T1>,
      std::tuple_element_t<Is, T2>>...
      >;
  };

  template<class T> struct dedup;
  template<class...Ts>
    struct dedup<std::tuple<Ts...>>
    {
      using type = decltype(std::tuple_cat(std::declval<Ts>()...)); 
    };

  using dups = typename impl<decltype(std::make_index_sequence<size>())>::type;

  using type = typename dedup<dups>::type;
};


int main()
{
  using t = interleave<std::tuple<int, char, float>, std::tuple<unsigned, double, const char*>>::type;
  std::cout << typeid(t).name() << std::endl;
}

答案 5 :(得分:0)

<强>目的:

获取类型别名:

Foo<int, double, char, const char*>

使用2个参数包:

using Pack1 = Pack<int, char>;
using Pack2 = Pack<double, const char*>;

然后交错它们:

typename ToFoo<Pack1, Pack2>::type

并执行相同的static_assert

using T1 = Foo<int, double, char, const char*>;
using T2 = typename ToFoo<Pack<int, char>, Pack<double, const char*>>::type;

static_assert(std::is_same<T1, T2>::value, "passed");

<强>解决方案:

我们可以将2个元组交错为1,如下所示:

template <class Tuple1, class Tuple2, std::size_t ... indices>
auto interleave(Tuple1 t1, Tuple2 t2, std::integer_sequence<std::size_t, indices...>)
{
    return std::tuple_cat(std::make_tuple(std::get<indices>(t1),
                                          std::get<indices>(t2))...);
}

template <class Tuple1, class Tuple2>
auto interleave(Tuple1 t1, Tuple2 t2)
{
    return interleave(t1, t2, std::make_index_sequence<std::tuple_size<Tuple1>::value>());
}

我们可以得到如下结果的交错元组的类型:

template<typename... Ts>
struct Pack 
{
    using type = std::tuple<Ts...>;
};

template<typename T0, typename T1>
struct Interleaved;

template<typename... P0, typename... P1>
struct Interleaved<Pack<P0...>, Pack<P1...>>
{
    using Pack0 = typename Pack<P0...>::type;
    using Pack1 = typename Pack<P1...>::type;

    using type = decltype(interleave(std::declval<Pack0>(), std::declval<Pack1>()));
};

然后我们可以使用std::tuple<Ts...>类型并将其“转换”为Foo<Ts...>,如下所示:

template<typename T>
struct TupleToFoo;

template<typename... Ts>
struct TupleToFoo<std::tuple<Ts...>>
{
    using type = Foo<Ts...>;
};

最后,我们将一个辅助类ToFoo包装起来,它需要2 Packs并定义一个类型别名:

template<typename T0, typename T1>
struct ToFoo;

template<typename... P0, typename... P1>
struct ToFoo<Pack<P0...>, Pack<P1...>>
{
    using type = typename TupleToFoo<typename Interleaved<Pack<int, char>, Pack<double, const char*>>::type>::type;
};

完整的工作示例:(coliru

#include <tuple>

template <class Tuple1, class Tuple2, std::size_t ... indices>
auto interleave(Tuple1 t1, Tuple2 t2, std::integer_sequence<std::size_t, indices...>)
{
    return std::tuple_cat(std::make_tuple(std::get<indices>(t1),
                                          std::get<indices>(t2))...);
}

template <class Tuple1, class Tuple2>
auto interleave(Tuple1 t1, Tuple2 t2)
{
    return interleave(t1, t2, std::make_index_sequence<std::tuple_size<Tuple1>::value>());
}

template<typename... Ts>
struct Pack 
{
    using type = std::tuple<Ts...>;
};

template<typename T0, typename T1>
struct Interleaved;

template<typename... P0, typename... P1>
struct Interleaved<Pack<P0...>, Pack<P1...>>
{
    using Pack0 = typename Pack<P0...>::type;
    using Pack1 = typename Pack<P1...>::type;

    using type = decltype(interleave(std::declval<Pack0>(), std::declval<Pack1>()));
};

template<typename... Ts>
struct Foo 
{};

template<typename T>
struct TupleToFoo;

template<typename... Ts>
struct TupleToFoo<std::tuple<Ts...>>
{
    using type = Foo<Ts...>;
};

template<typename T0, typename T1>
struct ToFoo;

template<typename... P0, typename... P1>
struct ToFoo<Pack<P0...>, Pack<P1...>>
{
    using type = typename TupleToFoo<typename Interleaved<Pack<int, char>, Pack<double, const char*>>::type>::type;
};


int main()
{
    using T1 = Foo<int, double, char, const char*>;
    using T2 = typename ToFoo<Pack<int, char>, Pack<double, const char*>>::type;

    static_assert(std::is_same<T1, T2>::value, "passed");
    return 0;
}