1

I am trying to implement a class system that uses callbacks to notify of certain events. I can think of 2 ways to do this:

#include <functional>
#include <iostream>

class A {
public:
    A(std::function<void(int)>&& func) : f(std::move(func)) {}
    void run() { f(2); }
    std::function<void(int)> f;
};

template <class F>
class B {
public:
    B(F&& func) : f(std::move(func)) {}
    void run() { f(2); }
    F f;
};

int main() {
    int n = 1;
    A a1([n](int b){std::cout << n+b << '\n';});
    B b1([n](int b){std::cout << n+b << '\n';});
    a1.run();
    b1.run();
}

What are the advantages/disadvantages of using these 2 approaches (having a template type for the callback type vs. using std::function)

0

1 Answer 1

2

I think it boils down to whether you can afford to have templated B because F can spread through your code quite quickly. Consider:

struct Foo{
    B<???> member;
};

If B is used mostly locally, F is fixed, or F should be exposed through Foo, this second approach can do everything that A can and doesn't have the overhead of std::function. (Measure!)

If you cannot afford that, you will need some form of type erasure, a.k.a std::function. But std::variant could be handy too.

I mean if you go with std::function, which has fixed signature, abstract callable Event class with virtual void operator()(int) is a viable option too. Well, without the lambdas, or with LambdaEvent using std::function underneath. Still this event hiearchy might provide more "type safety".

Please note that as written, B can accept any callable, not just void(int). Consider using std::invoke(f,2) instead of f(2).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.