How to assign member function pointer to non-member function pointer? [duplicate] - c++

I am trying to pass member function pointer to the c-style function (as it's lib in C)
The pointer it wants is defined as:
void (*)(int, const char*)
So the function I am trying to pass is:
void Application::onError(int error, const char *description)
I am trying to pass that with this code:
setCallback(bind(&Game::onError, this, placeholders::_1, placeholders::_2));
This gives me the following error:
cannot convert ‘std::_Bind_helper<false, void (Application::*)(Application*, int,
const char*), Application* const, const std::_Placeholder<1>&, const
std::_Placeholder<2>&>::type {aka std::_Bind<std::_Mem_fn<void (Application::*)
(Application*, int, const char*)>(Application*, std::_Placeholder<1>,
std::_Placeholder<2>)>}’ to ‘GLFWerrorfun {aka void (*)(int, const char*)}’ for
argument ‘1’ to ‘void (* glfwSetErrorCallback(GLFWerrorfun))(int, const char*)’
glfwSetErrorCallback(bind(&Application::onError, this, placeholders::_1, placeholders::_2));
Is there any way to successfully pass a member function as a bound function to the c-style function?

The result of std::bind is a complicated C++ object. It has to store all the bound arguments, for example. So it is most definitely not convertible to a pointer to function.
The callback specification you're dealing with apparently doesn't allow a "user data" payload, so there's nowhere to hide a pointer to a C++ object which you could use to invoke a non-static member funtion. This means you will have to call a global or static member function, or resort to a global/static member/per-thread variable to store the object pointer.
The only 100% portable way is to create a C linkage function to use as the callback. This does so, and uses a global object pointer to call your original onError():
Application *error_handling_application;
extern "C" void errorCallback(int error, const char *description)
{
error_handling_application->onError(error, description);
}
Note that quite often, you will encounter programs which use a static member function in place of my errorCallback. This works with most compilers on most platforms, but it is not guaranteed to work. The C library expects a function with C language linkage. A static member function can only have C++ language linkage. It is possible for the calling mechanism of a C function and a C++ function to differ (depends on ABI), which would result in a malformed call to the static member function passed in.

Since the member function also has the this pointer as implied argument, it is not of the type accepted by the C function. Hence, IMHO the only way is to generate a standalone function with C linkage
class A {
public: void func(int, const char*) const;
};
extern "C" {
void cfunc(void(*)(int, const char*));
void call_cfunc(const A*);
}
// in some source (non-header) file:
namespace {
const A*pa;
void afunc(int i, const char*s)
{ pa->func(i,s); }
}
void call_cfunc(const A*a)
{
pa = a;
cfunc(afunc);
}

Not directly, no. A C++ member function needs an implicit this pointer, which of course C has no idea about and won't pass.
The usual way around this is to introduce a "trampoline" as a class method, but perhaps there are prettier ways in more modern C++ variants.

Related

Cpp - pass a non-static function as argument [duplicate]

I am trying to pass member function pointer to the c-style function (as it's lib in C)
The pointer it wants is defined as:
void (*)(int, const char*)
So the function I am trying to pass is:
void Application::onError(int error, const char *description)
I am trying to pass that with this code:
setCallback(bind(&Game::onError, this, placeholders::_1, placeholders::_2));
This gives me the following error:
cannot convert ‘std::_Bind_helper<false, void (Application::*)(Application*, int,
const char*), Application* const, const std::_Placeholder<1>&, const
std::_Placeholder<2>&>::type {aka std::_Bind<std::_Mem_fn<void (Application::*)
(Application*, int, const char*)>(Application*, std::_Placeholder<1>,
std::_Placeholder<2>)>}’ to ‘GLFWerrorfun {aka void (*)(int, const char*)}’ for
argument ‘1’ to ‘void (* glfwSetErrorCallback(GLFWerrorfun))(int, const char*)’
glfwSetErrorCallback(bind(&Application::onError, this, placeholders::_1, placeholders::_2));
Is there any way to successfully pass a member function as a bound function to the c-style function?
The result of std::bind is a complicated C++ object. It has to store all the bound arguments, for example. So it is most definitely not convertible to a pointer to function.
The callback specification you're dealing with apparently doesn't allow a "user data" payload, so there's nowhere to hide a pointer to a C++ object which you could use to invoke a non-static member funtion. This means you will have to call a global or static member function, or resort to a global/static member/per-thread variable to store the object pointer.
The only 100% portable way is to create a C linkage function to use as the callback. This does so, and uses a global object pointer to call your original onError():
Application *error_handling_application;
extern "C" void errorCallback(int error, const char *description)
{
error_handling_application->onError(error, description);
}
Note that quite often, you will encounter programs which use a static member function in place of my errorCallback. This works with most compilers on most platforms, but it is not guaranteed to work. The C library expects a function with C language linkage. A static member function can only have C++ language linkage. It is possible for the calling mechanism of a C function and a C++ function to differ (depends on ABI), which would result in a malformed call to the static member function passed in.
Since the member function also has the this pointer as implied argument, it is not of the type accepted by the C function. Hence, IMHO the only way is to generate a standalone function with C linkage
class A {
public: void func(int, const char*) const;
};
extern "C" {
void cfunc(void(*)(int, const char*));
void call_cfunc(const A*);
}
// in some source (non-header) file:
namespace {
const A*pa;
void afunc(int i, const char*s)
{ pa->func(i,s); }
}
void call_cfunc(const A*a)
{
pa = a;
cfunc(afunc);
}
Not directly, no. A C++ member function needs an implicit this pointer, which of course C has no idea about and won't pass.
The usual way around this is to introduce a "trampoline" as a class method, but perhaps there are prettier ways in more modern C++ variants.

invalid use of non-static member function in qsort C++

here is my function in class SuffixArray:
int pstrcmp(const void *a, const void *b) {
return strcmp((const char *)*(char **)a, (const char *)*(char **)b);
}
I used this comparison function in qsort:
qsort(ap, len1+len2, sizeof(char *),pstrcmp);
which ap is a pointer array of suffix
When I compile it, there is an error:
invalid use of non-static member function
and I use notepad++ to compile it, it provide that
error: cannot convert 'SuffixArray::pstrcmp' from type 'int (SuffixArray::)(const void*, const void*)' to type 'int (*)(const void*, const void*)'
qsort(ap, len1+len2, sizeof(char *),pstrcmp);
is there anyone can help me?
In C++ you need to pass a free-standing function or a static member function (as opposed to a non-static member function) to qsort, because calling conventions of non-static member functions require an instance to be passed.
You have two solutions to this problem:
Move the declaration of pstrcmp out of the SuffixArray class, or
Declare pstrcmp static in the class.

Passing member function pointer to the c-style function

I am trying to pass member function pointer to the c-style function (as it's lib in C)
The pointer it wants is defined as:
void (*)(int, const char*)
So the function I am trying to pass is:
void Application::onError(int error, const char *description)
I am trying to pass that with this code:
setCallback(bind(&Game::onError, this, placeholders::_1, placeholders::_2));
This gives me the following error:
cannot convert ‘std::_Bind_helper<false, void (Application::*)(Application*, int,
const char*), Application* const, const std::_Placeholder<1>&, const
std::_Placeholder<2>&>::type {aka std::_Bind<std::_Mem_fn<void (Application::*)
(Application*, int, const char*)>(Application*, std::_Placeholder<1>,
std::_Placeholder<2>)>}’ to ‘GLFWerrorfun {aka void (*)(int, const char*)}’ for
argument ‘1’ to ‘void (* glfwSetErrorCallback(GLFWerrorfun))(int, const char*)’
glfwSetErrorCallback(bind(&Application::onError, this, placeholders::_1, placeholders::_2));
Is there any way to successfully pass a member function as a bound function to the c-style function?
The result of std::bind is a complicated C++ object. It has to store all the bound arguments, for example. So it is most definitely not convertible to a pointer to function.
The callback specification you're dealing with apparently doesn't allow a "user data" payload, so there's nowhere to hide a pointer to a C++ object which you could use to invoke a non-static member funtion. This means you will have to call a global or static member function, or resort to a global/static member/per-thread variable to store the object pointer.
The only 100% portable way is to create a C linkage function to use as the callback. This does so, and uses a global object pointer to call your original onError():
Application *error_handling_application;
extern "C" void errorCallback(int error, const char *description)
{
error_handling_application->onError(error, description);
}
Note that quite often, you will encounter programs which use a static member function in place of my errorCallback. This works with most compilers on most platforms, but it is not guaranteed to work. The C library expects a function with C language linkage. A static member function can only have C++ language linkage. It is possible for the calling mechanism of a C function and a C++ function to differ (depends on ABI), which would result in a malformed call to the static member function passed in.
Since the member function also has the this pointer as implied argument, it is not of the type accepted by the C function. Hence, IMHO the only way is to generate a standalone function with C linkage
class A {
public: void func(int, const char*) const;
};
extern "C" {
void cfunc(void(*)(int, const char*));
void call_cfunc(const A*);
}
// in some source (non-header) file:
namespace {
const A*pa;
void afunc(int i, const char*s)
{ pa->func(i,s); }
}
void call_cfunc(const A*a)
{
pa = a;
cfunc(afunc);
}
Not directly, no. A C++ member function needs an implicit this pointer, which of course C has no idea about and won't pass.
The usual way around this is to introduce a "trampoline" as a class method, but perhaps there are prettier ways in more modern C++ variants.

Why pointer to non-const member function can't point const member function and opposite?

What is the reason why pointers to member functions, can't point to const member functions?
struct A {
void g() {};
void f() const {}
};
Later in code:
void (A::* fun)() = &A::f;
This code produces:
error: cannot convert ‘void (A::*)()const’ to ‘void (A::*)()’ in initialization
Of course it compiles with &A::g instead of &A::f.
In opposite situation:
void (A::* fun)() const = &A::g;
The error is:
error: cannot convert ‘void (A::*)()’ to ‘void (A::*)()const’ in initialization
The second case is rather clear. const pointer isn't expected to modify the object so it can't hold the function which does it. But why it's not possible to assign const member function to non-const member function as in the first case?
It looks like the rule for normal pointers where casting const to non-const would allow to modify the value, but I don't see the point here, where const-correctness is checked in function definition, before such assignment.
What is the reason why pointers to member functions, can't point to const member functions?
Because the const modifier is part of the function signature. Once you declare a function pointer, that function pointer can only be used to assign pointers to function that have the same function signature.
Non-static member functions have an extra hidden this parameter. Given the existence of that that extra hidden parameter, a non-static void A::f() const; behaves much like void A__f(const A *__this), and the behaviour you see for member functions models the behaviour for non-member functions.
void f(void *);
void (*pf)(const void *) = f; // also an error
As for whether it could break on any implementation, I suppose in theory, an implementation is permitted to read a void * parameter from a different register than a const void * parameter, and if so, the result of the conversion (were it valid) could not be used to call f properly. I have no idea why any implementor would make such a decision, and I don't know of any real implementation that does so, but it's one allowed by the standard.

An odd C++ error: test.cpp:15: error: passing ‘const *’ as ‘this’ argument of ‘*’ discards qualifiers

I'm having some trouble with a particular piece of code, if anyone can enlighten me on this matter it would be greatly appreciated, I've isolated the problem down in the following sample:
#include <iostream>
using namespace std;
class testing{
int test();
int test1(const testing& test2);
};
int testing::test(){
return 1;
}
int testing::test1(const testing& test2){
test2.test();
return 1;
}
So what could possibly have cause the following error:
test.cpp:15: error: passing ‘const testing’ as ‘this’ argument of ‘int testing::test()’ discards qualifiers
Thanks a lot!
The problem is calling a non-const function test2.test() on a const object test2 from testing::test1.
testing::test1 gets test2 as a parameter const testing &test2. So within testing::test1, test2const. Then in the first line of the function:
test2.test()
The testing::test function is called on test2. That function is not declared with const at the signature end, so it may modify the object it is called on (the this pointer implicitly passed to it), and even though it does not, the compiler assumes so. By letting you call it there, the compiler would let you modify a const variable without an explicit cast, which C++ is not supposed to allow. Therefore to explain the error message:
test.cpp:15: error: passing ‘const testing’ as ‘this’ argument of ‘int testing::test()’ discards qualifiers
this refers to the object the member function (testing::test) operates on, and in this case it is not const, because testing::test was not declared with const, and thus the mismatch is detected when trying to make a non-const pointer (this) refer to a const object (testing), ignoring the const qualifier.
To solve this, decide whether the testing::test function should ever need to modify the object it is called on (the way it is written now it does not, as all it does is return 1, however that may change, so you need to think at what its intended functionality is). If it should, then obviously calling it on a const object is bad, although you can use const_cast to ask the compiler to override that, but this is dangerous. If it should not, then mark it const, so that it can be called on const objects as well:
class testing{
int test1() const;
// ...
}
int testing::test() const {
// ...
}
Because of the definition of the member function test1:
int testing::test1(const testing& test2){
test2.test();
return 1;
}
You are passing in a const reference of for the variable test2.
That means that you cannot modify any member of test2 and you cannot call any member function that is not const or is not static.
Here is how you can fix:
int testing::test() const {
return 1;
}
The extra const at the end tells the compiler that you are not planning on modifying the content of the current object (and if you do you will get a different compiling error).
The line:
test2.test()
is calling a non const function, even though test2 is a const reference. That's the problem. You can fix this by making testing::test a const function.
testing::test1(const testing& test2) is expecting the passed object to be const, and it will give you an error if you either modify the values of it's variables, or access any methods thereof that are not explicitly defined as const.
Since the test() method doesn't actually change any data, best practice is to set it const, as follows:
class testing{
int test() const;
int test1(const testing& test2);
};
int testing::test() const {
return 1;
}
Alternatively, just remove the word const when defining the arguments for test1(), and it will allow you to access any of the passed object's methods at your leisure.
For a quick and dirt solution, try compiling with -fpermissive as often suggested by the compiler itself (which is probably what VisualStudio compilers do, being that Windows users seldom report this problem).