Constructor arguments from tuple

后端 未结 5 929
礼貌的吻别
礼貌的吻别 2020-12-01 19:41

Suppose I have a template which is parametrized by a class type and a number of argument types. a set of arguments matching these types are stored in a tuple. How can one pa

相关标签:
5条回答
  • 2020-12-01 19:59

    C++17 has std::make_from_tuple for this:

    template <typename T, typename... Args>
    struct foo
    {
      std::tuple<Args...> args;
      T gen() { return std::make_from_tuple<T>(args); }
    };
    
    0 讨论(0)
  • 2020-12-01 20:05

    Create a sequence of indexes from 0 through n-1:

    template<size_t... indexes>
    struct seq {};
    
    template<size_t n, size_t... indexes>
    struct make_seq: make_seq<n-1, n-1, indexes...> {};
    
    template<size_t... indexes>
    struct make_seq: make_seq<0, indexes...> {
      typedef seq<indexes...> type;
    };
    

    unpack them in parallel with your args, or as the index to get<> in your case.

    The goal is something like:

    template< typename T, typename Tuple, typename Indexes >
    struct repack;
    
    template< typename... Ts, size_t... indexes >
    struct repack< tuple<Ts...>, seq<indexes...> > {
      T operator()( tuple<Ts...> const& args ) const {
        return T( get<indexes>(args)... );
      }
    };
    

    use repack in your gen like this:

    T gen() {
      repack<T, tuple<Args...>, typename make_seq<sizeof...(Args)>::type> repacker;
      return repacker( args );
    }    
    
    0 讨论(0)
  • 2020-12-01 20:10

    You'll need to use the indices trick, which means a layer of indirection:

    template <std::size_t... Is>
    struct indices {};
    template <std::size_t N, std::size_t... Is>
    struct build_indices
      : build_indices<N-1, N-1, Is...> {};
    template <std::size_t... Is>
    struct build_indices<0, Is...> : indices<Is...> {};
    
    template<typename T, typename... Args>
    struct foo {
      tuple<Args...> args;
      T gen() { return gen(build_indices<sizeof...(Args)>{}); }
    private:
      template<std::size_t... Is>
      T gen(indices<Is...>) { return T(get<Is>(args)...); }
    };
    
    0 讨论(0)
  • 2020-12-01 20:11

    You need some template meta-programming machinery to achieve that.

    The easiest way to realize the argument dispatch is to exploit pack expansion on expressions which contain a packed compile-time sequence of integers. The template machinery is needed to build such a sequence (also see the remark at the end of this answer for more information on a proposal to standardize such a sequence).

    Supposing to have a class (template) index_range that encapsulates a compile-time range of integers [M, N) and a class (template) index_list that encapsulates a compile-time list of integers, this is how you would use them:

    template<typename T, typename... Args>
    struct foo
    {
        tuple<Args...> args;
    
        // Allows deducing an index list argument pack
        template<size_t... Is>
        T gen(index_list<Is...> const&)
        {
            return T(get<Is>(args)...); // This is the core of the mechanism
        }
    
        T gen()
        {
            return gen(
                index_range<0, sizeof...(Args)>() // Builds an index list
                );
        }
    };
    

    And here is a possible implementation of index_range and index_list:

    //===============================================================================
    // META-FUNCTIONS FOR CREATING INDEX LISTS
    
    // The structure that encapsulates index lists
    template <size_t... Is>
    struct index_list
    {
    };
    
    // Collects internal details for generating index ranges [MIN, MAX)
    namespace detail
    {
        // Declare primary template for index range builder
        template <size_t MIN, size_t N, size_t... Is>
        struct range_builder;
    
        // Base step
        template <size_t MIN, size_t... Is>
        struct range_builder<MIN, MIN, Is...>
        {
            typedef index_list<Is...> type;
        };
    
        // Induction step
        template <size_t MIN, size_t N, size_t... Is>
        struct range_builder : public range_builder<MIN, N - 1, N - 1, Is...>
        {
        };
    }
    
    // Meta-function that returns a [MIN, MAX) index range
    template<unsigned MIN, unsigned MAX>
    using index_range = typename detail::range_builder<MIN, MAX>::type;
    

    Also notice, that an interesting proposal by Jonathan Wakely exists to standardize an int_seq class template, which is something very similar to what I called index_list here.

    0 讨论(0)
  • 2020-12-01 20:18

    C++14 will add standard support for index_sequence:

    template<typename T, typename... Args>
    struct foo {
      tuple<Args...> args;
      T gen() { return gen_impl(std::index_sequence_for<Args...>()); }
    private:
      template <size_t... Indices>
      T gen_impl(std::index_sequence<Indices...>) { return T(std::get<Indices>(args)...); }
    };
    
    0 讨论(0)
提交回复
热议问题