Reputation: 615
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.
Upvotes: 1
Views: 122
Reputation: 1506
This happens because the constructor can't deduce the type of its class. If my wording sounds weird, perhaps this example will help:
template <class T>
class Example {
Example(const T&) { /*...*/ }
};
If I have a function template, such as template <class T> void f(const Example<T>&)
, I can't just do f(10)
. This is what your code boils down to. std::function
can't know its template parameters based on what you passed to its (non-explicit) constructor.
Note: this is, by the way, in the works for C++17.
Upvotes: 2
Reputation: 275936
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.
Upvotes: 2