简体   繁体   English

C ++函数指针和成员函数指针

[英]C++ function pointer and member function pointer

Is there a way to use a function pointer for both functions and member functions? 是否可以将函数指针用于函数和成员函数?

I want to create a kind of event-handle which can hold member functions of a class and at the same time it should be capable to have "normal" function pointers. 我想创建一种事件句柄,它可以容纳一个类的成员函数,同时它应该能够具有“普通”函数指针。

EDIT: I have found a solution. 编辑:我找到了一个解决方案。 Probably not the best one but one; 也许不是最好的,而是最好的一个。

Event.h 事件.h

#include <map>

class BasicEvent {

public:

    BasicEvent(int id) : eventId(id)
    {}

    int GetId() const
    { 
        return eventId;
    }

    virtual void ObjectMethode() {}

protected:

    const int eventId;

};

class BasicEventHandler {

public:

    void Trigger(BasicEvent* event)
    {
        if (this->eventMap.find(event->GetId()) != this->eventMap.end()) {
            eventMap[event->GetId()](event);
        }
    }

    void AddEvent(int id, std::function<int(BasicEvent*)> eventFunction)
    {
        eventMap[id] = eventFunction;
    }

    void RemoveEvent(int id)
    {
        this->eventMap.erase(id);
    }

private:

    std::map<int, std::function<int(BasicEvent*)>> eventMap;

};

main.cpp main.cpp

class CustomEvent : public BasicEvent {

public:

    CustomEvent(int id) : tq::BasicEvent(id)
    {
    x = 9;
    y = 8;
    }

    struct {
    int x;
    int y;
};

    void ObjectMethode()
    {
    std::cout << this->eventId << " Custom Event: X: " << x << " Y: " << y << '\n';
    }

};


int main() {
    BasicEventHandler myHandler;

    myHandler.AddEvent(0, [&](BasicEvent* event) {
        std::cout << " EVENT <" << event->GetId() << "> Triggered!\n";
    return 0;
    });

    myHandler.AddEvent(1, [&](tq::BasicEvent* event) {
    event->ObjectMethode();
    return 0;
    });

    myHandler.Trigger(&BasicEvent(0));
    myHandler.Trigger(&CustomEvent(1));

    return 0;
}

C++11 and Lambdas .. yay!! C ++ 11和Lambdas ..

So here we go.. 所以我们开始..

Let us have a function, your event handler which will take a predicate (a function that returns true or false) and two functions namely on_sucess and on_error . 让我们有一个函数,您的事件处理程序将使用一个谓词 (一个返回true或false的函数)和两个函数on_sucesson_error

If the test_predicate returns true then on_success shall be invoked, else on_error would be invoked. 如果test_predicate返回true那么on_success将被调用,否则on_error将被调用。

template<typename Predicate, typename OnSucess, typename OnError>
void single_event_handler (Predicate && test_predicate,
                           OnSucess  && on_success,
                           OnError   && on_error)
{
    if( test_predicate() )
        on_success();
    else
        on_error();
}

And now our caller side. 现在我们的呼叫方。 Here we have 3 functions that we want to fit into this pattern. 在这里,我们有3个函数要适合此模式。

bool is_even(int num) { return !(num % 2); }
void on_even_found() { std::cout << "Number passed is even\n"; }
void on_odd_found() { std::cout << "Number passed is odd\n"; };

But as you can see, the is_even function does not fit into the signature of test_predicate . 但是如您所见, is_even函数不适合test_predicate的签名。 is_even(int) takes a single argument, while test_predicate() takes none. is_even(int)接受一个参数,而test_predicate()接受任何参数。

So how do we fix this ? 那么我们该如何解决呢?

We wrap it into one more function and/or lambda, and then pass it. 我们将其包装到另一个函数和/或lambda中,然后将其传递。

Guiding Principle : Every problem can be solved by adding one more layer. 指导原则: 每个问题都可以通过增加一层来解决。

// wrap it in another function or lambda
auto is_5_even = []() { return is_even(5); };
auto is_4_even = []() { return is_even(4); };

And now once all the pieces of our puzzle is ready, we create our own event handler. 现在,一旦难题的所有内容准备就绪,我们就可以创建自己的事件处理程序。

// caller side - pair the final structure
single_event_handler(is_5_even, on_even_found, on_odd_found);
single_event_handler(is_4_even, on_even_found, on_odd_found);

Now this code can be implemented in pre C++11, by using bind and function pointer. 现在,可以使用绑定和函数指针在C ++ 11之前的版本中实现此代码。 Sadly std::bind and std::function were introduced in C++11 and you would have to use other alternatives such as boost library. 可悲的是std::bindstd::function是C ++ 11中引入的,您将不得不使用其他替代方法,例如boost库。

Moreover, another wrapper can be written on top of single_event_handler which can manage multiple events at once, but I think we will have to create another function register_event so that it can be used effectively. 此外,可以在single_event_handler之上编写另一个包装器,该包装器可以一次管理多个事件,但是我认为我们必须创建另一个函数register_event以便有效地使用它。

Here is the full working code, for your reference (compiled using g++ -std=c++11 ) 这是完整的工作代码,供您参考(使用g++ -std=c++11编译)

#include <iostream>

template<typename Predicate, typename OnSucess, typename OnError>
void single_event_handler (Predicate && test_predicate,
                           OnSucess  && on_success,
                           OnError   && on_error)
{
    if( test_predicate() )
        on_success();
    else
        on_error();
}

bool is_even(int num) { return !(num % 2); }
void on_even_found() { std::cout << "Number passed is even\n"; }
void on_odd_found() { std::cout << "Number passed is odd\n"; };

int main()
{
    // caller side
    auto is_5_even = []() { return is_even(5); };
    auto is_4_even = []() { return is_even(4); };

    single_event_handler(is_5_even, on_even_found, on_odd_found);
    single_event_handler(is_4_even, on_even_found, on_odd_found);

    return 0;
}

Accept your handler as a std::function , and clients can then pass in whatever they want. 接受您的处理程序作为std::function ,然后客户端可以传递他们想要的任何内容。 Be it functions, lambdas, other functors, you name it. 无论是功能,lambda,其他函子,您都可以命名。

The template will handle the details for you, and the clients can choose how they wish to be called. 该模板将为您处理详细信息,客户可以选择希望如何致电。

where will the member function get its "this" pointer? 成员函数将在何处获得其“ this”指针? the two functions cannot have the same signature. 这两个函数不能具有相同的签名。 Probably, your best bet will be to create a lambda, that will capture the "this", and send it to your event-handler. 最好的选择是创建一个lambda,它将捕获“ this”,并将其发送给事件处理程序。

std::function will be able to hold it for you. std::function将能够为您保留它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM