所以我有一些泛型类,它有两个函数作为参数。一个接受一个函数指针,一个接受一个std :: function。两者都有模板参数。
#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;
}
使用函数指针编译,但是使用std :: function则不会。为什么模板扣除失败?
Clang报道:
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.
答案 0 :(得分:2)
这是因为构造函数无法推断出它的类的类型。如果我的措辞听起来很奇怪,也许这个例子会有所帮助:
template <class T>
class Example {
Example(const T&) { /*...*/ }
};
如果我有一个功能模板,例如template <class T> void f(const Example<T>&)
,我就不能f(10)
。这就是您的代码归结为。 std::function
根据您传递给它的(非显式)构造函数,无法知道它的模板参数。
注意:顺便说一下,这是C ++ 17的工作原理。
答案 1 :(得分:2)
模板参数推断不起作用。
模板参数推导是一种模式匹配。对于某种类型example
,std::function<void(const std::shared_ptr<const Targ>&)>
是Targ
类型的对象吗?
不可转换为,但实际上已经是该类型的对象?
不,不是。
然而,它已经是一个函数指针(使用隐式衰减规则)。
有一个C ++ 17功能涉及从构造函数类型中推导出模板参数;在这种情况下,当C ++ 17或C ++ 20出现时,std::function
可能会或可能不会从函数指针中学习它自己的类型。我缺乏C ++ 17方面的专业知识。