Why Callback Functions Needs to Be Static When Declared in Class

Why callback functions needs to be static when declared in class

A member function is a function that need a class instance to be called on.
Members function cannot be called without providing the instance to call on to. That makes it harder to use sometimes.

A static function is almost like a global function : it don't need a class instance to be called on. So you only need to get the pointer to the function to be able to call it.

Take a look to std::function (or std::tr1::function or boost::function if your compiler doesn't provide it yet), it's useful in your case as it allow you to use anything that is callable (providing () syntax or operator ) as callback, including callable objects and member functions (see std::bind or boost::bind for this case).

Why are async callback socket methods usually static?

There is no specific reason that they should be static. It all depends on your design.

If the callback needs to access members in the class then it can be declared as a instance member. However, you will need to make sure that you correctly syncronize the access to the instance members because the callback can be invoked concurrently from different threads.

I guess the examples you looked at all passed the required data through to the callback through the IAsyncResult.AsyncState so did not require additional information from the class. If you can do this it can simplify your code, since you no longer need to worry about thread syncronization etc..

Update

Just to clarify, based on the comments it seems I should have beed more explicit. It is not that the static callback would be thread safe, but rather that in a design where the data required is passed to the callback and of course this data is not shared by other threads then locking is not required. And since the callback is passed all the data it requires, it does not need access to the class instance and can therefore be made static.

Callable being required to be static in C++ class template

You are passing the class member function so you need to have in your CallbackBuffer class something like:

void (Base<T>::*callback)(std::vector<T>);

// ...

void setCallback(void (Base<T>::*cb)(std::vector<T>)) {
callback = cb;
}

and in Base class:

Base() {
buffer.setCallback(&Base<T>::bufferHandler);
}

Demo

Using a C++ class member function (cannot be static) as a C callback function

It is not possible, at least with that handler_t signature.

While you can create a free function on your .cpp to wrap the member call, you need a pointer to the Foo instance:

void my_wrap(int foo, void* bar) {
Foo* some_foo_instance = ...;
some_foo_instance->handler(foo, bar);
}

int main(int argc, char **argv) {
set_handler(&my_wrap);
}

You need some void* to pass the Foo instance as a handler attribute:

// Header
typedef void (*handler_t)(int foo, void *bar, void* arg1);
void set_handler(handler_t h, void* arg1);

// Impl.
void set_handler(handler_t h, void* arg1) {
handler_ = h;
handler_arg1_ = arg1;
}

// cpp
void my_wrap(int foo, void* bar, void* arg1) {
Foo* some_foo_instance = static_cast<Foo*>(arg1);
some_foo_instance->handler(foo, bar);
}

// main
int main(int argc, char **argv) {
Foo some_concrete_instance;
set_handler(&my_wrap, static_cast<void*>(&some_concrete_instance));
}

What exactly is the difference between an anonymous function and a static anonymous function in PHP?

You're referring to Static Anonymous Functions [DOC] which are introduced as following in the documentation:

Anonymous functions may be declared statically. This prevents them from having the current class automatically bound to them. Objects may also not be bound to them at runtime.

If you compare that with the explanation of the static keyword in the context of class methods [DOC], this might make the relation more clear. These are introduced as following in the documentation:

Because static methods are callable without an instance of the object created, the pseudo-variable $this is not available inside methods declared as static.

So an actual difference is that you don't have $this bound / available within the anonymous function when it is static.

The reason why you get the suggestion within the IDE is that static anonymous functions give you a slightly better performance over the non-static variant. So unless you need $this within the function, you can safely use the static variant over the non-static one.


Anonymous functions have been introduced in PHP 5.3 [RFC] [5.3.0], with the addition of the static keyword in PHP 5.4.

In PHP 5.3 $this was not automatically bound when defined within a class (intentionally) which has been changed with PHP 5.4 and it is since then that $this is automatically bound for the (non-static) anonymous function.

Since PHP 7.4 you can find arrow functions [DOC] which also come in the static/non-static flavours. However:

Arrow functions support the same features as anonymous functions, except that using variables from the parent scope is always automatic.

It's not only $this that a (non-static) arrow function would bound, it is (even for static ones) that all variables from the parent scope are automatically in use when in use. So this may hit performance more than given the occasional benefit of static for anonymous functions.

NOTE: This is not only theoretical (you need to measure for performance comparisons) but it might also create the impression that all outer scope variables might be bound in the (static) arrow function. But, only those which have a literal variable expression (e.g. $var), not variable variables, not even superglobals but this (which errors in static context and therefore even if it might be bound there as well it would be useless), are available in the arrow function expression. You can safely use static over not using it with arrow functions as well if you're not making use of $this in the arrow function expression (just to make it explicit again with this answer).


As you haven't shared which IDE, it is only a guess to which concrete suggestion you're referring to. Our educated guess is Phpstorm with the EA inspections plugin:

[EA] This closure can be declared as static (better scoping; in some cases can improve performance).

From the Static closures can be used EA inspection. And with the further information:

Analyzes closures and suggests using static closures instead.

This can bring additional performance improvements, e.g. as here:

Also, by using static function () {} closures, we squeezed out another 15% of hydration performance when dealing with private properties.

(from the inspection description provided by Php Inspections ​(EA Ultimate)​ within Phpstorm)

C++ static member function as C callback needs to access non static reference

You can create a static member function or a pure 'C' function to do this, consider my example below:

/**
* C++ part
*/
class obj
{
public:
obj() {}
~obj() {}

void doSomething(int a, int b) { cout << "result = " << a+b << endl; }
};

/**
* C Part
*/
#ifdef __cplusplus
extern "C"
#endif
{
typedef void (*callback)(void* one, void* two, void* three);

callback g_ptr = NULL;
void* arg = NULL;

void c_lib_core (void)
{
printf ("C Lib core...\n");
if (g_ptr)
{
g_ptr(arg, NULL, NULL);
}
}

void set_callback (void* arg, callback ptr)
{
g_ptr = ptr;
}

void my_callback (void* one, void* two, void* three)
{
obj* my_obj = (obj*) one;

my_obj->doSomething(1,2);
}

#ifdef __cplusplus
}
#endif

int main (void)
{
obj a;

set_callback (&a, my_callback);

c_lib_core ();
}

Output:

C Lib core...
result = 3

I pass a pointer to the C++ object as argument 1. This allows the callback to cast it back to C++ and call it. The c_lib_core stuff is just so I can simulate the callback of the callback function for testing purposes. This, along with the global variables will be in the C code somewhere. You only need to implement a single C function and set ARG1 to your object and you are good to go.

How to use non-static methods as callback functions and reference `this`?

In javascript the class methods are not bind to its scope when you call them through a reference.

Your code will work correctly if you bind the function to the instance, or if you wrap the call in a function.

Some examples of how you could rewrite the method1 in class ClassA to make things work.

Binding the context to the function:

  method1() {
const instance = new ClassB();
this.method2(instance.method3.bind(instance));
}

Wrapping the call:

  method1() {
this.method2(()=>new ClassB().method3());
}

Using C++ non-static member functions as callbacks and class scope issue

If you're really stuck with typedef void (*fnctPtr)(int input);, then you have to provide a pointer to a function that takes a int as parameter and returns nothing.

When you' providing a pointer-to-member function of class B taking an int and returning nothng, you really provide either something that can be seen as:

  • either function taking two arguments, the instance of the classB and an int.
  • or a virtual function that need to lookup in B instance to know what function taking two arguments (B and int) to call.

There is no way to make any of those fit into the first definition.

You may find a hack (keeping an instance globally and using it inside an helper function would be one), but this is highly dependent of the full problem.



Related Topics



Leave a reply



Submit