Chris Stathis Chris Stathis - 23 days ago 8
C++ Question

Passing a function with templated parameters as an argument, with function pointers vs. std::function

So I have some generic class with two functions that take functions as parameters. One takes a function pointer and one takes a std::function. Both have a template parameter.

#include <functional>
#include <memory>

namespace {
void example(const std::shared_ptr<const int>&) {}
}

class Generic {
public:
Generic() {}
virtual ~Generic() {}
template <typename Targ>
void doWork(std::function<void(const std::shared_ptr<const Targ>&)> arg) {}

template <typename Targ>
void doWork2(void(*function)(const std::shared_ptr<const Targ>&)) {}
};

class Special : public Generic {
public:
Special() {
//doWork(&example); // Fail!
doWork<int>(&example); // OK!
std::function<void(const std::shared_ptr<const int>&)> func = &example;
doWork(func); // OK!
doWork2(&example); // OK!
}
};

int main(int argc, char** argv) {
Special special;
return 0;
}


With the function pointer it compiles, but with the std::function it does not. Why does template deduction fail here?

Clang reports:

example.cpp:27:9: error: no matching member function for call to 'doWork'
doWork(&example);
^~~~~~
example.cpp:14:10: note: candidate template ignored: could not match 'function<void (const shared_ptr<const type-parameter-0-0> &)>' against 'void (*)(const std::shared_ptr<const int> &)'
void doWork(std::function<void(const std::shared_ptr<const Targ>&)> arg) {
^
1 error generated.

Answer

Template argument deduction does not work like that.

Template argument deduction is a pattern match. Is example an object of type std::function<void(const std::shared_ptr<const Targ>&)> for some type Targ?

Not convertible-to, but actually an object of that type already?

No, it is not.

It is, however, already a function pointer (using the implicit decay rules).

There is a C++17 feature that involve deducing template arguments from constructor types; std::function may or may not be instrumented to learn its own type from a function pointer when C++17 or C++20 comes out in this situation. I lack expertise in C++17 to be certain.