使用函数内部绑定调用

Using bind inside of function call

本文关键字:绑定 调用 内部 函数      更新时间:2023-10-16

好吧,所以我已经有一个工作示例,但是我只是想清理它。

目前,我有一个带回调例程的订阅样式的事件系统。

我在为其添加常规功能和类成员功能时没有问题。

但我喜欢通过超载我的事件来清理它。

目前它可以做类似的事情:

template <class T>
class EventObject
{
public:
    void subscribe(const T& arg)
    {
        this->events.push_back(arg);
    }
std::vector<T> events;
}

然后在我的主要用途中使用:

void someCallback(const std::string& line)
{
    cout <<line;
}
typedef  std::function<void(const std::string& line)> onMessageCallbackFunction;
EventObject<onMessageCallbackFunction> messageCallback;
messageCallback.subscribe(someCallback);

现在,当我使用类成员功能时,泡菜会挺身而出。我讨厌在通过函数之前必须内在绑定该功能。它使代码看起来很脏。

例如:

class B
{
    void callbk(const std::string& line) {}
};
B b;
using std::placeholders::_1;
onMessageCallbackFunction memfunc = std::bind(&B::callbk, b, _1);
messageCallback.subscribe(memfunc);

现在是可以的,但是看起来很糟糕。语法是什么,所以我可以预先形成:

messageCallback.subscribe(&B::callbk, b);

尝试了几个,但我似乎无法正确。

不是什么:

template <class J>
void subscribe(J::T cls,T& t); //Nope.
void subscribe(J&& cls,T& t); //Nope.

超关闭:( thx tobi)

template< class J, class... Args >
void subscribe(void(J::*funct)(Args), J& inst) {
    using std::placeholders::_1;
    subscribe(std::bind(funct, inst, _1));
}

现在只需要通用参数列表。

我的建议是使用lambda(std::bind是过时的,因为Lambdas几乎在各个方面都优越)。

单独拼出Lambda永远不会受到伤害。这样做没有表现成本。编译器将出现不必要的副本。

我还将使用std ::函数存储您的信号并从兼容传递功能类型转换。

您的呼叫站点代码看起来像这样,我认为您会同意这是干净和表现力的:

EventObject<void(std::string)> messageCallback;
B b;
auto handler = [&b](std::string const& line)
{
    b.callbk(line);
};
messageCallback.subscribe(handler);

完成示例:

#include <string>
#include <vector>
#include <functional>
#include <type_traits>
template<class Sig> struct EventObject;
template<class R, class...Args>
struct EventObject<R (Args...)>
{
    using slot_type = std::function<R(Args...)>;
    template
    <
        class F,
        typename std::enable_if
        <
            std::is_constructible
            <
                slot_type, 
                typename std::decay<F>::type
            >::value
        >::type * = nullptr
    >
    void subscribe(F&& f)
    {
        subscribers_.emplace_back(std::forward<F>(f));
    }
    std::vector<slot_type> subscribers_;
};
class B
{
public:
    void callbk(const std::string& line) {}
};
int main()
{
    EventObject<void(std::string)> messageCallback;
    B b;
    auto handler = [&b](std::string const& line)
    {
        b.callbk(line);
    };
    messageCallback.subscribe(handler);
}

语法是什么,所以我可以预先形成:

messageCallback.subscribe(&B::callbk, b);

您的界面已经允许传递任何可召唤,并且没有理由使其更复杂。EventObject不应知道回调是免费的功能还是其他功能。我完全同意std::bind很乏味,看起来不好,我宁愿使用lambda:

EventObject<onMessageCallbackFunction> messageCallback;
B b;
messageCallback.subscribe([&b](const std::string& line){return b.callbk(line);});

ps:我不确定我是否会理解您使用tempalte的动机。似乎您只想与onMessageCallbackFunction s一起使用它,因此仅存储其中的向量应该很好。

pps:为了完整的目的,您可以在方法中隐藏bind

#include <vector>
#include <string>
#include <iostream>
#include <functional>
using std::placeholders::_1;
template <class T>
class EventObject {
public:
    void subscribe(const T& arg)
    {
        this->events.push_back(arg);
    }
    template<typename C>
    void subscribe(void(C::*mem_fun)(const std::string&),C& c){
        subscribe(std::bind(mem_fun,c,_1));
    }       
    std::vector<T> events;
};
typedef  std::function<void(const std::string& line)> onMessageCallbackFunction;
struct B {
    void callbk(const std::string& line) {}
};
int main(){
    EventObject<onMessageCallbackFunction> messageCallback;
    B b;
    messageCallback.subscribe(&B::callbk,b);
}

这仅适用于返回void并返回string的成员函数,但我什至不愿意使其成为通用并使用lambdas。