绑定绑定函数作为参数

时间:2014-12-30 01:19:55

标签: c++ c++11 bind function-pointers boost-bind

我有一个类foo,其方法bar带有可调用的东西(函数指针/仿函数)。这个可调用的东西应该作为带有第三种方法doit方法的绑定元素传递给另一个方法bar_cb

#include <functional>
#include <iostream>

class foo {
public:
    template<typename T>
    void bar(T&& t) {
        std::cout << "bar\n";
        doit(std::bind(&foo::template bar_cb<T>, this, std::forward<T>(t)));
    }

    template<typename T>
    void doit(T&& t) {
        std::cout << "doit\n";
        t();
    }

    template<typename T>
    void bar_cb(T&& t) {
        std::cout << "bar_cb\n";
        t();
    }
};


void lala() {
    std::cout << "lala\n";
}

class functor {
public:
    void operator()() {
        std::cout << "functor::operator()\n";
    }
};


int main() {
    foo f;
    functor fn;
    f.bar(fn);
    f.bar(std::bind(lala));  // error

    return 0;
}

这适用于functors但不适用于绑定函数作为foo::bar(我的示例中为lala)的参数。是否有可能将一个不可知的类型传递给一个方法并将它作为参数绑定到另一个方法中(如果是这样的话)?

我知道我可以在函数周围包含一个仿函数(例如std::function)但是因为我可以调用一个不可知的类型,我认为有一种方法可以绑定它(我想我只是缺少了简单的事情。)

Here指向示例的链接。

1 个答案:

答案 0 :(得分:2)

主要问题是您的bar_cb(T&&)没有推断出模板参数,因为在使用带有某些模板参数&foo::template bar_cb<X>的{​​{1}}时实际指定了模板参数。然而,X表达式将复制绑定函数,即,它可能具有或可能不具有将被推导出的类型。另外,bind()传递std::bind() - 表达式,而是调用它们!

最简单的解决方法是使用bind()来绑定函数,而是使用lambda函数:

std::bind()

这样做让编译器推导出template<typename T> void bar(T&& t) { std::cout << "bar\n"; doit([=](){ this->bar_cb(t); }); } 的更正参数类型(使用C ++ 14,你可能想要使用捕获bar_cb(),尽管你的[this,t = std::forward<T>(t)]仍然赢了#39;看到左值。)

要通过另一个bar_cb() - 表达式传递已经bind() - 表达式,而不让bind()考虑内部bind() - 表达式bind() - 表达你需要让它看起来好像不是bind() - 表达式。您可以使用瘦函数包装器执行此操作:

bind()

由于存储在template <typename Fun> class unbinder { Fun fun; public: template <typename F> unbinder(F&& fun): fun(std::forward<F>(fun)) {} template <typename... Args> auto operator()(Args&&... args) const -> decltype(fun(std::forward<Args>(args)...)) { return fun(std::forward<Args>(args)...); } }; template <typename Fun> auto unbind(Fun&& fun) -> unbinder<Fun> { return unbinder<Fun>(std::forward<Fun>(fun)); } 表达式中的函数将由左值传递,因此您需要为bind()提供不同的声明,但是:

bar_cb()

这样,您可以使用

注册template<typename T> void bar_cb(T& t) { ... } - 表达式
bind()

如果您想使用f.bar(unbind(std::bind(lala))); ,您需要f.bar(std::bind(lala))的条件定义:如果它收到bar() - 表达式,则需要自动隐藏它是bind()一个bind() - 表达式,应用unbind()或类似的东西:

template<typename T>
typename std::enable_if<!std::is_bind_expression<typename std::decay<T>::type>::value>::type
bar(T&& t) {
    std::cout << "bar (non-bind)\n";
    doit(std::bind(&foo::template bar_cb<T>, this, std::forward<T>(t)));
}
template<typename T>
typename std::enable_if<std::is_bind_expression<typename std::decay<T>::type>::value>::type
bar(T&& t) {
    std::cout << "bar (bind)\n";
    doit(std::bind(&foo::template bar_cb<unbinder<T>>, this, unbind(std::forward<T>(t))));
}