【问题标题】:Passing a function with templated parameters as an argument, with function pointers vs. std::function将带有模板参数的函数作为参数传递,带有函数指针与 std::function
【发布时间】:2016-11-14 19:30:48
【问题描述】:

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

【问题讨论】:

  • example 不是std::function,并且可能会从这个函数构造几个std::function
  • @Jarod42 但&amp;example 是函数指针,我可以将函数指针作为std::function 传递,不是吗?

标签: c++ c++11 templates


【解决方案1】:

模板参数推导不是那样工作的。

模板参数推导是一种模式匹配。 examplestd::function&lt;void(const std::shared_ptr&lt;const Targ&gt;&amp;)&gt; 类型的对象,对于某些类型 Targ

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

不,不是。

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

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

【讨论】:

  • 可以肯定的是,我缺乏 C++17 方面的专业知识。我想像你一样缺乏专业知识。 :-)
【解决方案2】:

发生这种情况是因为构造函数无法推断其类的类型。如果我的措辞听起来很奇怪,也许这个例子会有所帮助:

template <class T>
class Example {
    Example(const T&) { /*...*/  }
};

如果我有一个函数模板,比如template &lt;class T&gt; void f(const Example&lt;T&gt;&amp;),我不能只做f(10)。这就是您的代码归结为的内容。 std::function 无法根据您传递给其(非显式)构造函数的内容知道其模板参数。

注意:顺便说一下,这是在为 C++17 开发的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-25
    • 2019-10-20
    • 2015-01-20
    • 2010-11-19
    • 2017-06-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多