5

This is a followup question to "unpacking" a tuple to call a matching function pointer, which asked how to provide the values from a std::tuple as arguments to a function in a generic way. A solution given there was the following:

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

template<int N, int ...S>
struct gens : gens<N-1, N-1, S...> { };

template<int ...S>
struct gens<0, S...>
{
   typedef seq<S...> type;
};

double foo(int x, float y, double z)
{
   return x + y + z;
}

template <typename... Args>
struct save_it_for_later
{
   std::tuple<Args...> params;
   double (*func)(Args...);

   double delayed_dispatch()
   {
    return callFunc(typename gens<sizeof...(Args)>::type());
   }

   template<int ...S>
   double callFunc(seq<S...>)
   {
    return func(std::get<S>(params) ...);
   }
};

int main(void)
{
   std::tuple<int, float, double> t = std::make_tuple(1, 1.2, 5);
   save_it_for_later<int,float, double> saved = {t, foo};
   std::cout << saved.delayed_dispatch() << std::endl;
}

My question is whether there's way to make an alternate version of save_it_for_later which takes only foo as a template argument, so that we don't have to provide foo 's parameter types as a template argument (or bake its return type into save_it_for_later). Something like

int main(void) {
   ...
   save_it_for_later2<foo> saved = {t};
   ...
}

I'd be equally fine with some sort of macro wrapping foo to extract the required types:

int main(void) {
   ...
   save_it_for_later<MACRO_USING_DECLTYPE_OR_SOMESUCH(foo)> saved = {t};
   ...
}

This concern seems orthogonal enough to the original question to warrant its own ticket.

Community
  • 1
  • 1
factotum
  • 348
  • 3
  • 9
  • What is `foo`? If it's a general functor with multiple overloads of `operator()`, which overload should you use? If `foo` is going to be, for example, just a function pointer or `std::function`, this is easy to do. The general case is hard. – Pradhan Jun 18 '15 at 22:23
  • `foo` is just a function pointer, as in the example above. – factotum Jun 18 '15 at 22:41

2 Answers2

5
#include <tuple>
#include <utility>

template <typename> struct save_it_for_later_t;
template <typename Result, typename... Args>
struct save_it_for_later_t<Result (*)(Args...)> {
    std::tuple<Args...>   params;
    Result              (*fun)(Args...);
    template <typename... Params>
    save_it_for_later_t(Result (*fun)(Args...), Params&&... params)
        : params(std::forward<Params>(params)...)
        , fun(fun) {
    }
    // ... 
};
template <typename Result, typename... Args, typename... Params>
save_it_for_later_t<Result(*)(Args...)>
save_it_for_later(Result (*fun)(Args...), Params&&... params) {
    return save_it_for_later_t<Result(*)(Args...)>(fun, std::forward<Params>(params)...);
}

double foo(float, float, double);
int main() {
    auto saved = save_it_for_later(foo, 1.2f, 3.4f, 5.6);
    // ...
}
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • Great! For bonus points, is it possible to make `foo` itself a template parameter (rather than a class member)? Long story, but in my situation---which is different than the artificial example above---this would actually be incredibly useful. – factotum Jun 19 '15 at 00:21
  • Actually, before getting to the bonus points, your solution doesn't seem quite right; can you provide a full solution which you've checked compiles? – factotum Jun 19 '15 at 05:16
  • @factotum: yes, there were a few minor typos. These are fixed. – Dietmar Kühl Jun 19 '15 at 06:14
1

I just sheepishly discovered that I'd asked a similar question last year (Unpacking arguments of a functional parameter to a C++ template class), which yields an answer here too:

#include <functional>
#include <iostream>
#include <tuple>

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

template<int N, int ...S>
struct gens : gens<N-1, N-1, S...> { };

template<int ...S>
struct gens<0, S...>
{
   typedef seq<S...> type;
};

double foo(int x, float y, double z)
{
   return x + y + z;
}

template<typename T>
struct save_it_for_later;

template <typename Result, typename... Args>
struct save_it_for_later<Result(Args...)>
{
   std::tuple<Args...> params;
   Result (*func)(Args...);

   Result delayed_dispatch()
   {
    return callFunc(typename gens<sizeof...(Args)>::type());
   }

   template<int ...S>
   Result callFunc(seq<S...>)
   {
    return func(std::get<S>(params) ...);
   }
};

int main(void)
{
   std::tuple<int, float, double> t = std::make_tuple(1, 1.2, 5);
   save_it_for_later<decltype(foo)> saved = {t, foo};
   std::cout << saved.delayed_dispatch() << std::endl;
}
Community
  • 1
  • 1
factotum
  • 348
  • 3
  • 9