In general, unless you use cast, you should trust g++.
While it is true that none of the function types you mention can be exported to use from within C, this is not what you're asking. You are asking about what functions you can pass as a function pointer.
To answer what you can pass, I think it is more constructive to understand what you cannot pass. You cannot pass anything that requires additional arguments not explicitly stated in the arguments list.
So, no non-static methods. They need an implicit "this". C will not know to pass it. Then again, the compiler won't let you.
No capturing lambdas. They require an implicit argument with the actual lambda body.
What you can pass are function pointers that require no implicit context. As a point of fact, you went ahead and listed them:
- Function pointer. It doesn't matter whether it is a standard function or a template, so long as the template is fully resolved. This is not a problem. Any syntax you write that results in a function pointer will automatically fully resolve the template.
- Non capturing lambdas. This is a special work-around introduced by C++11 when it introduced lambdas. Since it is possible to do so, the compiler does the explicit conversion required to make it happen.
- Static methods. Since they are static, they do not get passed an implicit
this
, so they are okay.
The last one bears expanding on. Many C callback mechanisms get a function pointer and a void* opaq. The following is a standard and fairly safe of using them with a C++ class:
class Something {
void callback() {
// Body goes here
}
static void exported_callback(void *opaq) {
static_cast<Something*>(opaq)->callback();
}
}
And then do:
Something something;
register_callback(Something::exported_callback, &something);
Edited to add:
The only reason this works is because the C++ calling convention and the C calling convention are identical when no implicit arguments are passed. There is a difference in name mangling, but it is not relevant when you pass a function pointer, as the sole purpose of name mangling is to allow the linker to find the correct function's address.
Had you tried that trick with a callback expecting, e.g., an stdcall or pascal calling convention, this scheme would fall flat on its face.
This, however, is not unique to static methods, lambdas and template functions. Even a standard function would fail under those circumstances.
Sadly, when you define a function pointer to an stdcall type, gcc ignores you:
#define stdcall __attribute__((stdcall))
typedef stdcall void (*callback_type)(void *);
results in:
test.cpp:2:45: warning: ‘stdcall’ attribute ignored [-Wattributes]
typedef stdcall void (*callback_type)(void *);