Obtain Argument Index while Unpacking Argument List with Variadic Templates

后端 未结 2 1914
生来不讨喜
生来不讨喜 2020-12-18 11:57

I need to obtain the index of an argument while unpacking and converting argument list. Is there any solution for the following problem:



        
相关标签:
2条回答
  • 2020-12-18 12:13

    The simplest solution is surely to not use a vector of void*; just use the values directly:

    template<typename...Arg>
    void call_test(Arg const&...arg) {
      test(arg...);
    }
    

    (Or some variant on that theme.) But I suppose you wanted to do something other than just call test.

    If you really want the indices, use what's called here the "indices trick". You should be able to search for that.

    0 讨论(0)
  • 2020-12-18 12:19

    This is how I would do it. First of all, you will need some machinery to create compile-time sequences of integers:

    using namespace std;
    
    //===========================================================================
    // 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<size_t MIN, size_t MAX>
    using index_range = typename detail::range_builder<MIN, MAX>::type;
    
    //===========================================================================
    

    Then, you could use that machinery for realizing the function call, exploiting the power of argument pack expansion:

    #include <iostream>
    #include <vector>
    #include <string>
    
    void test(int a, std::string b, bool c)
    {
        cout << a << "," << b << "," << c << endl ;
    }
    
    namespace detail
    {
        // This is the function that does the real work.
        template<typename... Ts, size_t... Is>
        void call_test(const vector<void*>& params, index_list<Is...>)
        {
            test((*static_cast<Ts*>(params[Is]))...);
        }
    }
    
    // This function just creates the compile-time integer sequence and 
    // forwards to another function that performs the real work.
    // In other words, this is a proxy that hides the complexity of the
    // machinery from the client.
    template <typename... ARG>
    void call_test(const vector<void*>& params)
    {
        detail::call_test<ARG...>(params, index_range<0, sizeof...(ARG)>());
    }
    
    int main(int argc, char **argv)
    {
        int    a = 1;
        string b = "string";
        bool c   = false;
        vector<void*> v(3);
        v[0] = &a;
        v[1] = &b;
        v[2] = &c;
    
        call_test<int,string,bool>(v);
    }
    
    0 讨论(0)
提交回复
热议问题