【问题标题】:c++11: std::bind for sub-class member-functionsc++11: 子类成员函数的 std::bind
【发布时间】:2015-01-03 14:06:07
【问题描述】:

我想调用类的运行时绑定函数,这些函数从公共类“Bindable”继承绑定能力。这真的可能吗?

这是一个肯定缺少很多模板参数和命名空间的存根:

#include <iostream>     // std::cout
#include <functional>   // std::bind
#include <map>          // std::map

class Bindable {
public:
    void bindFunction (int x, auto newFn) {
        mFns.insert(std::pair<int, auto>(x,newFn));
    }
    void invokeFunction (int key) {
        mFns.at(key)();
    }

protected:
    std::map<int, function> mFns;
};

class A : Bindable {
    void funAone (void) {
        cout << "called funAone" <<std::endl;
    }
    void funAtwo (void) {
        cout << "called funAtwo" <<std::endl;
    }
};

class B : Bindable {
    void funBone (void) {
        cout << "called funBone" <<std::endl;
    }
    void funBtwo (void) {
        cout << "called funBtwo" <<std::endl;
    }
};

int main() {
    A a;
    B b;

    a.bindFunction(1, &A::funAone);
    a.bindFunction(2, &A::funAtwo);
    b.bindFunction(1, &B::funBone);
    b.bindFunction(2, &B::funBtwo);

    a.invokeFunction(1);
    a.invokeFunction(2);
    b.invokeFunction(1);
    b.invokeFunction(2);
}

【问题讨论】:

  • 通过硬编码成员函数的签名并使用 CRTP like here ?
  • 谢谢,看起来不错!
  • 也许值得再问一个问题,但是:有没有办法将具有不同签名的函数存储在“Bindable”中的同一个 std::map 中?
  • 您可以在here 和here 以及许多其他问题中找到答案
  • 从我推导出的第一个链接this.(只是在这里)

标签: c++ c++11


【解决方案1】:

选项 #1

使用CRTP习语了解可以存储什么类型的成员函数指针:

template <typename T>
struct Bindable {   
    void bindFunction (int x, void(T::*newFn)()) {
        mFns.insert(std::make_pair(x,newFn));
    }
    void invokeFunction (int key) {
        (static_cast<T*>(this)->*mFns.at(key))();
    }

protected:
    std::map<int, void(T::*)()> mFns;
};

struct A : Bindable<A> {
    void funAone (void) {
        std::cout << "called funAone" <<std::endl;
    }
    void funAtwo (void) {
        std::cout << "called funAtwo" <<std::endl;
    }
};

DEMO 1

选项 #2

使用类型擦除并将bindFunction 设为函数模板:

struct Bindable {    
    template <typename T, typename std::enable_if<std::is_base_of<Bindable, T>{}, int>::type = 0>
    void bindFunction (int x, void(T::*newFn)()) {
        mFns.insert(std::make_pair(x, std::bind(newFn, static_cast<T*>(this))));
    }
    void invokeFunction (int key) {
        mFns.at(key)();
    }
protected:
    std::map<int, std::function<void()>> mFns;
};

struct A : Bindable {
    void funAone (void) {
        std::cout << "called funAone" <<std::endl;
    }
    void funAtwo (void) {
        std::cout << "called funAtwo" <<std::endl;
    }
};

DEMO 2

在这两种情况下,您都可以使用如下代码:

int main() {
    A a;
    B b;

    a.bindFunction(1, &A::funAone);
    a.bindFunction(2, &A::funAtwo);
    b.bindFunction(1, &B::funBone);
    b.bindFunction(2, &B::funBtwo);

    a.invokeFunction(1);
    a.invokeFunction(2);
    b.invokeFunction(1);
    b.invokeFunction(2);
}

输出:

called funAone
called funAtwo
called funBone
called funBtwo

【讨论】:

  • 您出于什么原因将类更改为结构?
  • @DPF 只是为了让成员默认为public 并默认拥有public 继承
【解决方案2】:

是的,可以使用 std::bind。请注意,auto 不能用作函数或模板参数。

#include <iostream>     // std::cout
#include <functional>   // std::bind
#include <map>          // std::map

class Bindable {
public:
    typedef std::function<void()> Function;
    void bindFunction (int x, Function newFn) {
        mFns.insert(std::pair<int, Function>(x,newFn));
    }
    void invokeFunction (int key) {
        mFns.at(key)();
    }

protected:
    std::map<int, Function > mFns;
};

class A : public Bindable {
public:
    void funAone (void) {
        std::cout << "called funAone" <<std::endl;
    }
    void funAtwo (void) {
        std::cout << "called funAtwo" <<std::endl;
    }
};

class B : public Bindable {
public:
    void funBone (void) {
        std::cout << "called funBone" <<std::endl;
    }
    void funBtwo (void) {
        std::cout << "called funBtwo" <<std::endl;
    }
};

int main() {
    A a;
    B b;

    a.bindFunction(1, std::bind(&A::funAone, a)); // more than one way to bind
    a.bindFunction(2, std::bind(&A::funAtwo, &a)); // the object parameter
    b.bindFunction(1, std::bind(&B::funBone, b));
    b.bindFunction(2, std::bind(&B::funBtwo, &b));

    a.invokeFunction(1);
    a.invokeFunction(2);
    b.invokeFunction(1);
    b.invokeFunction(2);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-09
    • 2021-04-27
    • 2019-12-02
    • 1970-01-01
    • 2013-01-08
    相关资源
    最近更新 更多