Return several arguments for another function by a single function

前端 未结 6 1887
余生分开走
余生分开走 2021-01-03 05:31

This question was closed as exact duplicate since I chose a misleading question title. It was not wrong but suggested an issue often discussed, e.g. in this question. Since

6条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2021-01-03 05:48

    I don't think there is any direct way of doing what you want, but here is a C++11 technique that I use in several places of my code. The basic idea is to use a template function which I've called call_on_tuple to take a function argument f as well as a tuple of further arguments, expand the tuple and call the function on the expanded list of arguments:

    template 
    typename std::result_of::type
    call_on_tuple(Fun&& f, std::tuple&& tup, indices)
    { return f(std::get(tup)...); }
    

    So the idea is that instead of calling

    length(arguments());
    

    you would call

    call_on_tuple(length,arguments());
    

    This assumes that arguments() is changed so it returns a std::tuple (this is basically the idea from the question you cited).

    Now the difficult part is how to get the Is... argument pack, which is a pack of integers 0,1,2,... used to number the elements of the tuple.

    If you are sure you'll always have three arguments, you could use 0,1,2 literally, but if the ambition is to make this work for any n-ary function, we need another trick, which has been described by other posts, for example in several answers to this post.

    It's a trick to transform the number of arguments, i.e. sizeof...(Args) into a list of integers 0,1,...,sizeof...(Args):

    I'll put this trick and the implementation of call_on_tuple in a namespace detail:

    namespace detail {
    
      template 
      struct indices
      { };
    
      template 
      struct index_maker : index_maker
      { };
    
      template 
      struct index_maker<0,Is...>
      { typedef indices type; };
    
    
      template 
      typename std::enable_if::type>::value,
                  typename std::result_of::type>::type
      call_on_tuple(Fun&& f, std::tuple&& tup, indices)
      { return f(std::get(tup)...); }
    }
    

    Now the actual function call_on_tuple is defined in global namespace like this:

    template 
    typename std::enable_if::type>::value,
                typename std::result_of::type>::type
    call_on_tuple(Fun&& f, std::tuple&& tup)
    {
      using std::tuple;
      using std::forward;
      using detail::index_maker;
    
      return detail::call_on_tuple
        (forward(f),forward>(tup),typename index_maker::type());
    }
    

    It basically calls detail::index_maker to generate the list of increasing integers and then calls detail::call_on_tuple with that.

    As a result, you can do this:

    int length(int x, int y, int z)
    { return x + y + z; }
    
    std::tuple arguments()
    { return std::tuple { 1 , 2 , 3 }; }
    
    int main()
    {
      std::cout << call_on_tuple(length,arguments()) << std::endl;
      return 0;
    }
    

    which is hopefully close enough to what you needed.

    Note. I have also added an enable_if to ensure this is only used with functions f that actually return a value. You can readily make another implementation for functions that return void.

    Sorry again for closing your question prematurely.

    PS. You'll need to add the following include statements to test this:

    #include 
    #include 
    #include 
    

提交回复
热议问题