【问题标题】:How do I strip a tuple<> back into a variadic template list of types?如何将元组<> 剥离回可变参数模板类型列表?
【发布时间】:2013-03-03 08:48:17
【问题描述】:

有没有办法剥离 std::tuple&lt;T...&gt; 以将其恢复为 T...

示例

假设vct&lt;T...&gt; 是一个预先存在的 可变类模板

using U = std::tuple<int,char,std::string>;
using X = vct<int,char,std::string>;
using Y = vct< strip<U> >;            // should be same as X

备注

我知道std::tuple_element,但我需要所有元素,以可用作T... 的形式

作为参考,我找到了这个question,它是类似的,但我的需求稍微简单一些(所以我希望有一个更简单的解决方案):我需要的只是tuple 中的类型列表- 我不关心tuple 实例的实际值。

【问题讨论】:

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


    【解决方案1】:
    template<typename>
    struct strip;
    
    template<typename ...T>
    struct strip<std::tuple<T...>>
    {
       using type = vct<T...>;
    };
    

    然后将其用作:

    using Y = strip<U>::type;
    

    现在YX 相同。

    【讨论】:

      【解决方案2】:

      不,这是不可能的。参数包是类型推导的结果,不能在其他上下文中产生。

      您可以通过这种方式执行类似于您要求的操作:

      template<template<typename...> class T, typename>
      struct instantiate_with_arg_pack { };
      
      template<template<typename...> class T, typename... Ts>
      struct instantiate_with_arg_pack<T, std::tuple<Ts...>>
      {
          using type = T<Ts...>;
      };
      
      template<typename... Ts>
      struct vct { };
      
      int main()
      {
          using U = std::tuple<int,char,std::string>;
          using X = vct<int,char,std::string>;
          using Y = instantiate_with_arg_pack<vct, U>::type;
      }
      

      实际上,您不需要将参数包保存在元组中:任何可变参数类模板都可以:

      template<template<typename...> class T, typename>
      struct instantiate_with_arg_pack { };
      
      template<
          template<typename...> class T, 
          template<typename...> class U, // <===
          typename... Ts
          >
      struct instantiate_with_arg_pack<T, U<Ts...>>
      //                                   ^^^^^^^^
      {
          using type = T<Ts...>;
      };
      
      template<typename... Ts>
      struct vct { };
      
      int main()
      {
          using U = std::tuple<int,char,std::string>;
          using X = vct<int,char,std::string>;
          using Y = instantiate_with_arg_pack<vct, X>::type;
          //                                        ^
      
          // Won't fire
          static_assert(
              std::is_same<Y, vct<int,char,std::string>>::value, 
              "Error!");
      }
      

      这是live example

      【讨论】:

        【解决方案3】:

        你不能直接“返回”一个参数包,所以你需要的是这样的:

        template< typename... Ts >
        struct vct
        { ... };
        
        template< typename T >
        struct make_vct;
        
        template< typename... Ts >
        struct make_vct< std::tuple< Ts... > >
        {
            typedef vct< Ts... > type;
        };
        

        并使用

        using Y = make_vct< U >::type;
        

        【讨论】:

          【解决方案4】:

          这里的目标是能够将参数包从模板实例复制到另一个模板。我没有将其限制为tuple,因为...为什么将其限制为tuple

          template<template<typename...>class Target, typename Src>
          struct copy_pack_types;
          
          template<template<typename...>class Target, template<typename...>class Src, typename... Ts>
          struct copy_pack_types< Target, Src<Ts...> > {
            typedef Target<Ts...> type;
          };
          
          template<template<typename... Ts>class Target, typename Src>
          using CopyPackTypes = typename copy_pack_types<Target, Src>::type;
          
          #include <string>
          #include <tuple>
          template<typename... Ts> struct vct;
          template<typename... Ts> struct vct2;
          using U = std::tuple<int,char,std::string>;
          using X = vct<int,char,std::string>;
          using Y = CopyPackTypes< vct, U >;            // should be same as X
          using Z = CopyPackTypes< vct2, U >;            // should be different from X
          
          #include <iostream>
          #include <type_traits>
          int main() {
            std::cout << std::is_same< X, Y >::value << "\n";
            std::cout << std::is_same< Z, Y >::value << "\n";
            std::cout << std::is_same< Z, vct2<int,char,std::string> >::value << "\n";
          }
          

          如预期的那样,输出为“1 0 1”。

          CopyPackTypes 采用目标模板和从参数包构造的源类型作为其唯一参数。然后它将参数包复制到目标模板。

          一个标准的技术是携带参数包是创建一个其他没有用的类型,比如:

          template<typename...>
          struct types {};
          

          它仅作为类型列表的占位符存在。然后,您可以将其中一些传递给另一个模板,并且每个包不会“踩”对方。当您需要将其应用到目标模板时,您可以使用类似上述“CopyPackTypes”的内容来应用它。

          类似的技术用于索引包:

          template<size_t...>
          struct seq {};
          

          否则无用的类型是“黑板”,用于携带大量参数。

          【讨论】:

            【解决方案5】:

            使用 c++17 std::apply.

            using U = std::tuple<int, char, std::string>;
            using X = vct<int, char, std::string>;
            using Y = vct<strip<U>>; // should be same as X
            
            auto my_y = std::apply(
                    [](auto... ts) {
                        using Y = vct<decltype(ts)...>;
                        return Y{};
                    },
                    U{});
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2023-02-05
              • 1970-01-01
              • 1970-01-01
              • 2020-11-16
              • 2010-12-05
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多