2

This is what I currently have

void test(int& i, float& f) {}

template <class... Ts, class F>
void update(F&& f)
{
  //Use Ts here
}

int main()
{
  update<int, float>(test);
}

But I need to explicitly call update with <int, float> because I want to use it for metaprogramming.

It would be nice if this could be deduced automatically from the function

void test(int& i, float& f) {}

template <class... Ts>
void update(std::function<void(Ts&...)> f)
{
   //use Ts here
}
int main()
{
  //error: no matching function for call to 'update'
  update(test);
}
Maik Klein
  • 15,548
  • 27
  • 101
  • 197
  • [boost function traits](http://www.boost.org/doc/libs/1_57_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html) or [other function traits](https://functionalcpp.wordpress.com/2013/08/05/function-traits/) may help. – Jarod42 Dec 02 '15 at 19:46
  • This has been answered several times before on stackoverflow. Basically the compiler cannot know in advance that `void(*)(int&, float&)` is convertible to `std::function`, because it can't see the constructors of the `function` specialization until it after deduces `Ts...`, but there is no way to deduce that in advance (for all the compiler knows, every specialization of `std::function` could be convertible from that function pointer). – Jonathan Wakely Dec 02 '15 at 19:59

3 Answers3

4

simply provide a converting overload:

#include <iostream>
#include <functional>

void test(int& i, float& f) {}


template <class... Ts>
void update(std::function<void(Ts&...)> f)
{
    //use Ts here
}

// this overload matches the function pointer and forwards the function
// pointer in a std::function as required
template<class... Ts>
void update(void (*fp)(Ts&...))
{
    update(std::function<void(Ts&...)>(fp));
}

int main()
{
    //error: no matching function for call to 'update'
    update(test);
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
2

Of course you can :)

Consider this:

#include <functional>

int test(int& , float& ) { return 0;}
double test2(char* ) { return 0; }

template <class F>
void update(F&& )
{
  typedef typename F::result_type R;
}

template <class R, class... ARGS>
  auto make_function(R (*f)(ARGS...)) {
    return std::function<R (ARGS...)>(f);
}

int main()
{

  update(make_function(&test));
  update(make_function(&test2));
}
SergeyA
  • 61,605
  • 5
  • 78
  • 137
2

When the arguments are function pointers this is easy enough to do: just add this overload:

template <class R, class... Ts>
void update(R (*f)(Ts...)) {
    update(std::function<R(Ts...)>(f));
}

If you get something arbitrary, it is impossible to do:

struct foo {
    template <typename T0, Typename T1>
    void operator()(T0, T1);
};

Which arguments are to be deduced?

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380