代码之家  ›  专栏  ›  技术社区  ›  egst

将元组连接为类型

  •  6
  • egst  · 技术社区  · 7 年前

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

    我需要连接多个元组,但是作为类型,不是像 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 回复  |  直到 7 年前
        1
  •  3
  •   felix    7 年前

    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
  •  4
  •   max66    7 年前

    玩太晚了吗?

    我提出以下解决方案

    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 也可以使用类型的通用容器。如果A STD::元组 -只有解决方案对您足够,您可以将其简化如下

    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::元组 .

    这是个问题?

    我不知道,因为我不知道怎么用 类别:类型 .

    总之…避免强加于此 cat<Ts...>::type 仅当全部 Ts... 是类型容器(具有相同的容器),它很简单:的主版本 cat 仅声明但未定义

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

    并且引入了一个具有单个类型的额外专门化(但仅当它是类型容器时)。

    template <template <typename ...> class C, typename ... Ts1>
    struct cat<C<Ts1...>>
     { using type = C<Ts1...>; };
    
        3
  •  3
  •   Red.Wave P.W    7 年前

    一行直接模板别名如何:

    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};