将元组连接为类型

时间:2018-11-20 13:29:43

标签: c++ c++11 variadic-templates template-meta-programming stdtuple

我正在尝试练习一些模板编程。也许有一种标准的方法可以做到这一点,我很感谢这样的答案,但是我的主要目标是练习模板编程技术,所以我尝试自己实现:

我需要连接多个元组,但是作为类型,不像std::cat_tuple那样。所以我需要像cat<std::tuple<int, float>, std::tuple<char, bool>, ...>这样的东西来获取std::tuple<int, float, char, bool, ...>作为类型。

我当前的尝试失败,并出现is not a template错误:

/* Concat tuples as types: */
template <typename first_t, typename... rest_t> struct cat {
    using type = typename _cat<first_t, typename cat<rest_t...>::type>::type;
                          ^^^^ cat is not a template
};
template <typename first_t, typename second_t>
struct cat<first_t, second_t> {
    using type = typename _cat<first_t, second_t>::type;
                          ^^^^ cat is not a template
};
// Concat two tuples:
template <typename, typename> struct _cat;
template <typename tuple_t, typename first_t, typename... rest_t>
struct _cat<tuple_t, std::tuple<first_t, rest_t...>> {
    using type = typename _cat<typename append<first_t, tuple_t>::type, std::tuple<rest_t...>>::type;
};
template <typename tuple_t, typename first_t>
struct _cat<tuple_t, std::tuple<first_t>> {
    using type = typename append<first_t, tuple_t>::type;
};
// Prepend element to tuple:
template <typename, typename> struct prepend;
template <typename elem_t, typename... tuple_elem_t>
struct prepend<elem_t, std::tuple<tuple_elem_t...>> {
    using type = std::tuple<elem_t, tuple_elem_t...>;
};
// Apppend element to tuple:
template <typename, typename> struct append;
template <typename elem_t, typename... tuple_elem_t>
struct append<elem_t, std::tuple<tuple_elem_t...>> {
    using type = std::tuple<tuple_elem_t..., elem_t>;
};

可能是什么原因导致错误?

这是一个好方法吗?可以用一种更简单的方法解决它,但我希望它具有多种用途(带有添加/添加操作等)。

3 个答案:

答案 0 :(得分:4)

玩太晚了吗?

我提出以下解决方案

ModelE

请注意,此解决方案不仅适用于template <typename T, typename ...> struct cat { using type = T; }; template <template <typename ...> class C, typename ... Ts1, typename ... Ts2, typename ... Ts3> struct cat<C<Ts1...>, C<Ts2...>, Ts3...> : public cat<C<Ts1..., Ts2...>, Ts3...> { }; 的可变列表,而且适用于类型的通用容器。如果仅使用std::tuple的解决方案就足够了,则可以按照以下说明进行简化

std::tuple

您可以测试

template <typename T, typename ...>
struct cat
 { using type = T; };

template <typename ... Ts1, typename ... Ts2, typename ... Ts3>
struct cat<std::tuple<Ts1...>, std::tuple<Ts2...>, Ts3...>
   : public cat<std::tuple<Ts1..., Ts2...>, Ts3...>
 { };

-编辑-

using t1 = typename cat<std::tuple<int, float>, std::tuple<char, bool>, std::tuple<long, char, double>>::type; using t2 = std::tuple<int, float, char, bool, long, char, double>; static_assert(std::is_same<t1, t2>::value, "!"); (谢谢!)在我的先例解决方案中指出了这一点

felix

即... std::is_same<int, typename cat<int>::type>::value == true 也在cat<T>::type不是T时定义。

这是问题吗?

我不知道,因为我不知道std::tuple的用法。

无论如何...避免强加cat<T>::type仅在所有cat<Ts...>::type是类型容器(具有相同容器)时才定义的事实,这很简单:Ts...的主版本仅声明但未定义

cat

并引入了一种附加的针对单个类型的专门化(但仅当它是类型容器时)。

template <typename, typename ...> // or also template <typename...>
struct cat;

答案 1 :(得分:3)

reordering定义之后,您的代码可以正常工作。

我认为模板元编程没有任何指导方针。可能是由于C ++委员会正在“积极”增强TMP,而使用TMP的人却很少。

这是我的Cat版本,它基本上遵循与您相同的结构:

template <class, class>
struct Cat;
template <class... First, class... Second>
struct Cat<std::tuple<First...>, std::tuple<Second...>> {
    using type = std::tuple<First..., Second...>;
};

答案 2 :(得分:3)

单线直接模板别名如何?

template<typename ... input_t>
using tuple_cat_t=
decltype(std::tuple_cat(
    std::declval<input_t>()...
));


tuple_cat_t<
    std::tuple<int,float>,
    std::tuple<int>
    > test{1,1.0f,2};