How to pass method(as callback) as param to method? - c++

I have static method in my Utils class
This is definition
/*static*/ void Utils::copy_files(void(*progress_callback)(int, int),
std::string const & path_from,
std::string const & path_to)
{
....
}
And here using
void TV_DepthCamAgent::progress_callback(int count, int copied_file)
{
printf("Progress :: %d :: %d\n", count, copied_file);
}
void TV_DepthCamAgent::foo()
{
...
shared::Utils::copy_files(progress_callback, path_from_copy, path_to_copy);
...
}
And this is an errors that I get
E0167 argument of type "void (TV_DepthCamAgent::)(int count, int copied_file)" is incompatible with parameter of type "void ()(int, int)"
Error C3867 'TV_DepthCamAgent::progress_callback': non-standard syntax; use '&' to create a pointer to member
What am I doing wrong?

Since you've tagged this C++ i'm assuming you want a C++ solution.
Since C++11 we can use std::function instead of the awkward C style pointer-to-function syntax.
So void(*progress_callback)(int, int) becomes std::function<void(int, int)> progress_callback
In regards to why you get that error it is because to pass a function pointer you must pass the function by reference
...
shared::Utils::copy_files(&progress_callback);
...
You must then pass the required arguments when you call it in copy_files.
You should use std::function and std::bind for this instead of the C style you seem to be writing in

Related

boost function bind compiled with a conversion error

I have the following code
#include <boost/function.hpp>
#include <boost/bind.hpp>
class Foo {
public:
int getIfoo();
};
int Foo::getIfoo() {
return 5;
}
int main () {
boost::function<int (Foo)> getIntFoo;
getIntFoo = boost::bind( &Foo::getIfoo, _1 );
return 0;
}
When I compile with the following command g++ TestBoostBind.cpp I've got the following error
/includes/boost_1_60_0/boost/bind/mem_fn_template.hpp:35:36: error: invalid conversion from ‘const Foo*’ to ‘Foo*’ [-fpermissive]
BOOST_MEM_FN_RETURN (u.*f_)();
~~~~~~~^~
I'm confused about the source of the error whether it's originally from my code or the boost library. Does anyone know what the error means and how to fix it? I use g++ (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0 and boost.1.60
When binding to a member function, the first argument needs to be a pointer or a reference to the object to call the function on. It specifically can't be a value (an actual object instance). The boost::bind function have special cases for these two alternatives to generate the correct objects. It does not have any special case for passing by value.
Therefore you need to define getIntFoo as a function taking a pointer to Foo:
boost::function<int (Foo*)> getIntFoo;
Or a reference:
boost::function<int (Foo&)> getIntFoo;
You could try to use std::mem_fn to achieve the same goal:
Foo f;
std::function<int(Foo &)> getIntFoo = std::mem_fn(&Foo::getIfoo);
int ret = getIntFoo(f);
or if you need pointer argument, std::function could resolve this for you:
Foo f;
std::function<int(Foo *)> getIntFoo = std::mem_fn(&Foo::getIfoo);
int ret = getIntFoo(&f);
boost have its own alternative

Pointer static method that points to no static method

I've been trying to make a pointer function that points to a method doing something like this(visual C++):
struct test
{
int tst(int a)
{
return a * 4;
}
};
// ok, this the visual C++ compiler does not accept it... (mingw accept it)
int(*tstptr)(int) = (int(*)(int))&test::tst;
Then I've done something like this:
struct Dx
{
int SomeMethod()
{
return 4;
}
};
struct Dy
{
static int(*pSomeMethod)();
};
int(Dy::*pSomeMethod)() = (int( Dy::*)())&Dx::SomeMethod;
So far so good, this compiles without problems, but if I try call her:
Dy::pSomeMethod();
The compiler returns me:
Error 1 error LNK2001: external symbol "public: static int (__stdcall
* Dy::pSomeMethod) (void)" (? PSomeMethod#Dy##2P6GHXZA) unresolved
which I do not understand, because it is not suppose pSomeMethod he is not pointing at SomeMethod ?
The type of &test::tst is int (test::*) (int), which is a member function pointer.
You are trying to convert it to a regular pointer type, which is not possible because they are completely different.
That's why you will have this type cast error:
error C2440: 'type cast' :
cannot convert from 'int (__thiscall test::* )(int)' to 'int (__cdecl *)(int)'
int(Dy::*pSomeMethod)() = (int( Dy::*)())&Dx::SomeMethod;
Type Checked, so no complain from compiler.
As for:
Dy::pSomeMethod();
This a __cdecl.
But, SomeMethod is a __thiscall, which means it's really like this
int SomeMethod( Dx &this);
So, linker can't find a match.
You simply can't call non-static method without object of class Dx.
Your declaration of pSomeMethod defines a pointer to a function within class Dy that returns an int. You want to declare it as it appears in the linker error:
int (*Dy::pSomeMethod)();
which is a member of Dy that is a pointer to a function returning an int.
What you're trying to do won't work, since Dx::SomeMethod is a member function of Dx, which needs a this pointer. Calling thru pSomeMethod won't have one.
When done right, you can just assign the address of the function to the pointer without using a cast.

Microsoft Detours - unable to hook __thiscall function

I am trying to hook an undocumented function which has the signature:
(void(__thiscall*)(int arg1, int arg2))0x6142E0;
I have looked at the detours sample "member" where it explains:
By default, C++ member functions use the __thiscall calling
convention. In order to Detour a member function, both the trampoline
and the detour must have exactly the same calling convention as the
target function. Unfortunately, the VC compiler does not support a
__thiscall, so the only way to create legal detour and trampoline functions is by making them class members of a "detour" class.
In addition, C++ does not support converting a pointer to a member
function to an arbitrary pointer. To get a raw pointer, the address
of the member function must be moved into a temporary member-function
pointer, then passed by taking it's address, then de-referencing it.
Fortunately, the compiler will optimize the code to remove the extra
pointer operations.
I have copied some code from the example and modified it but I cant seem to get this to work(original example code here):
class CDetour {
public:
void Mine_Target(int arg1, int arg2);
static void (CDetour::* Real_Target)(int arg1, int arg2);
};
void CDetour::Mine_Target(int arg1, int arg2) {
printf(" CDetour::Mine_Target! (this:%p)\n", this);
(this->*Real_Target)(arg1, arg2);
}
void (CDetour::* CDetour::Real_Target)(int arg1, int arg2) = (void(CDetour::*)(int arg1, int arg2)) (0x6142E0);
void hoo()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)CDetour::Real_Target, (PVOID)(&(PVOID&)CDetour::Mine_Target));
DetourTransactionCommit();
}
I am not sure how to get this to work. The a bow code has two compiler errors:
void (CDetour::* CDetour::Real_Target)(int arg1, int arg2) = (void(CDetour::*)(int arg1, int arg2)) (0x6142E0);
//Error C2440 'type cast': cannot convert from 'int' to 'void (__thiscall CDetour::* )(int,int)'
and:
DetourAttach(&(PVOID&)CDetour::Real_Target, (PVOID)(&(PVOID&)CDetour::Mine_Target));
//Error C2440 'type cast': cannot convert from 'void (__thiscall CDetour::* )(int,int)' to 'PVOID &'
I hope someone can help me in the right direction because I am bout to give up on hooking __thiscall functions...
I am considering writing a global "__declspec(naken) void MyFunc(int, int)" function with inline assembly in order to preserve the "this pointer" as suggested here.
Detours is fairly old. Explicit compiler support for __thiscall is fairly new. Looks like there's support for it in Visual C++ 2005 and later. It seems the Detours documentation was never updated.
Try using a more powerful alternative http://www.nektra.com/products/deviare-api-hook-windows/deviare-in-process/ which is open source.

c++ pointers to overloaded functions

I'm trying to expose a overloaded function using boost::python.
the function prototypes are:
#define FMS_lvl2_DLL_API __declspec(dllexport)
void FMS_lvl2_DLL_API write(const char *key, const char* data);
void FMS_lvl2_DLL_API write(string& key, const char* data);
void FMS_lvl2_DLL_API write(int key, const char *data);
I'v seen this answer: How do I specify a pointer to an overloaded function?
doing this:
BOOST_PYTHON_MODULE(python_bridge)
{
class_<FMS_logic::logical_file, boost::noncopyable>("logical_file")
.def("write", static_cast<void (*)(const char *, const char *)>( &FMS_logic::logical_file::write))
;
}
results with the following error:
error C2440: 'static_cast' : cannot convert from 'overloaded-function' to 'void (__cdecl *)(const char *,const char *)'
None of the functions with this name in scope match the target type
trying the following:
void (*f)(const char *, const char *) = &FMS_logic::logical_file::write;
results:
error C2440: 'initializing' : cannot convert from 'overloaded-function' to 'void (__cdecl *)(const char *,const char *)'
None of the functions with this name in scope match the target type
what's wrong and how to fix it?
EDIT
I forgotten to mention a few things:
I'm using vs2010 pro on win-7
write is a member function of logical_file
FMS_logic is a namespace
Well the second attemp should work, if write is a pure function. From your code it seems you do have a memberfunction. Pointers to member-functions are ugly, you'd rather use a function object.
However: you would have to post the whole code, it is not clear whether write is a member-function or not.
Edit: if it is a member-function of FMS_logic::logical_file the syntax would be:
void (FMS_logic::logical_file::*f)(const char *, const char *) = &FMS_logic::logical_file::write;
This just applies for non-static member function, i.e. if a function is static or logical_file is just a namespace it is as you wrote it before.
Your code doesn't work because your function pointer type is wrong. You need to include all type qualifiers (your DLL qualifier is missing) and, as Klemens said, the class name. Putting this together, your code should read
.def("write", static_cast<void FMS_lvl2_DLL_API
(FMS_logic::logical_file::*)(const char *, const char *)>
(&FMS_logic::logical_file::write))
Thanks for the hint with the static_cast<>, I had the same problem as you, just without the dllexport, and after adding the static_cast it works :-)

use external function as member-function pointer

Is it possible in C++ to create a function which is not defined in class A but can be treated like a method pointer? Eg.:
typedef bool (A::*MethodType)(int a);
MethodType g_someMethod = &A::SomeMethod;
Now, I want to create a new function AnotherMethod which is of the type MethodType. I have tried to do the following:
bool A_AnotherMethod(A* _this, int a) {
std::cout << __FUNCTION__ << "\n";
return true;
}
MethodType g_someMethod = A_AnotherMethod;
// ...
(this->*g_someMethod )(42);
But I get
error C2440: '=' : cannot convert from 'bool (__cdecl *)(A *,int)' to 'bool (__cdecl A::* )(int)'
How to do it correctly?
No, you can't. C++ does not have a feature similar to extension methods in C#.
p.s. Method pointers have clumsy syntax in C++ and are rarely used. But this is the way how they are defined in the language.