C++ 在函数调用内部使用bind

C++ 在函数调用内部使用bind,c++,callback,std-function,C++,Callback,Std Function,好的,我已经有了这个例子,但我只是想把它整理一下 目前,我有一个带有回调例程的订阅样式的事件系统 我可以将常规函数和类成员函数添加到它的存储变量中 但是我想通过重载Event.subscribe方法来清理它 目前它是这样做的: template <class T> class EventObject { public: void subscribe(const T& arg) { this->events.push_back(arg);

好的,我已经有了这个例子,但我只是想把它整理一下

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

我可以将常规函数和类成员函数添加到它的存储变量中

但是我想通过重载Event.subscribe方法来清理它

目前它是这样做的:

template <class T>
class EventObject
{
public:
    void subscribe(const T& arg)
    {
        this->events.push_back(arg);
    }
std::vector<T> events;
}
现在是的,它工作了,但它看起来很糟糕。我可以使用什么语法来执行:

messageCallback.subscribe(&B::callbk, b);
messageCallback.subscribe(&B::callbk, b);
我试了几次,但似乎都做不好

事实并非如此:

template <class J>
void subscribe(J::T cls,T& t); //Nope.
void subscribe(J&& cls,T& t); //Nope.
模板
无效认购(J::T cls,T&T)//不。
无效认购(J&cls、T&T)//不。
超级接近:(thx tobi)

模板
无效认购(无效(J::*函数)(参数),J&inst){
使用std::占位符::1;
订阅(std::bind(funct,inst,_1));
}
现在只需要修改参数列表

我可以使用什么语法来执行:

messageCallback.subscribe(&B::callbk, b);
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);});

这仅适用于返回
void
并返回
字符串的成员函数,但我甚至不想麻烦将其设置为通用的,只使用lambda。

我的建议是使用lambda(
std::bind
在它问世的那一天就已经过时了,因为lambda在几乎所有方面都优于lambda)

把lambda单独拼出来从来都没有坏处。这样做没有性能成本。编译器将删除不必要的副本

我还将使用std::function来存储信号,并从兼容的传入函数类型进行转换

然后,您的呼叫站点代码看起来是这样的,我想您会同意这是一个干净且富有表现力的代码:

EventObject<void(std::string)> messageCallback;
B b;

auto handler = [&b](std::string const& line)
{
    b.callbk(line);
};

messageCallback.subscribe(handler);
eventobjectmessagecallback;
B B;
自动处理程序=[&b](标准::字符串常量和行)
{
b、 callbk(行);
};
messageCallback.subscribe(处理程序);
完整示例:

#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);
}
#包括
#包括
#包括
#包括
模板结构EventObject;
模板
结构事件对象
{
使用slot_type=std::function;
模板
<
F类,
typename std::启用\u如果
<
std::是可构造的吗
<
槽型,
typename std::decation::type
>::价值
>::type*=nullptr
>
无效订阅(F&F)
{
订阅者向后安置(标准::向前(f));
}
std::向量订阅服务器;
};
B类
{
公众:
void callbk(const std::string&line){}
};
int main()
{
EventObject消息回调;
B B;
自动处理程序=[&b](标准::字符串常量和行)
{
b、 callbk(行);
};
messageCallback.subscribe(处理程序);
}

不确定,但我想我更喜欢lambdas而不是binddas。你可以看到它是如何在std::thread ctor(3)中实现的——这并不简单,所以你最好使用
std::function
@Slava。那么你会怎么做呢?关于这个问题有很多要说的。但是如果您有可用的boost,我会鼓励您使用boost.signals2它可以解决您将遇到的所有问题我将使用
std::function
std::bind
或lambdas(或两者)一起使用。不同的事件类型可能需要回调具有不同参数的函数。是的,但看起来我将失去在向量中搜索方法的合格地址的能力。如果我希望“取消”-订阅一个对象。因为函数的地址是基于Lambda的。@StevenVenham我很好奇,想得到你要的东西。它看起来不太糟糕,但我真的不想用它,而是依赖它lambdas@StevenVenham实际上,只有成员函数才能使用
字符串
,使其真正通用,这将有点复杂。更通用的东西是我一直在想的。因此,使用这个示例,为什么像:template void sub2(void(J::*funct)(slot_type),J&inst){}这样的东西不起作用呢?您需要传递一个指向J的指针以及成员函数指针。然后它会非常具体。
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);
}