使用模板化参数作为参数传递函数,使用函数指针与std :: function

时间:2016-11-14 19:30:48

标签: c++ c++11 templates

所以我有一些泛型类,它有两个函数作为参数。一个接受一个函数指针,一个接受一个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.

2 个答案:

答案 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)

模板参数推断不起作用。

模板参数推导是一种模式匹配。对于某种类型examplestd::function<void(const std::shared_ptr<const Targ>&)>Targ类型的对象吗?

不可转换为,但实际上已经是该类型的对象?

不,不是。

然而,它已经是一个函数指针(使用隐式衰减规则)。

有一个C ++ 17功能涉及从构造函数类型中推导出模板参数;在这种情况下,当C ++ 17或C ++ 20出现时,std::function可能会或可能不会从函数指针中学习它自己的类型。我缺乏C ++ 17方面的专业知识。