How to pass a function pointer to overloaded member function as parameter - c++

This is related to code generation.
I have a class A which is generated from model, in which I have two overloads of function f like below:
class A
{
public:
void f(int a){}
void f(int a, int b){}
}
I then have a separate part of the system which is not generated from model, but written in hand crafted C++. Here I would like to access the function f on an object. From the model I can pass data to the hand crafted part of the system, but not the other way around, since the generated file is not available for compilation when I build my hand crafted code.
My idea is to pass a function pointer from the model to where I need it. This, as I have understood it so far, includes static_cast to solve the overload issue and then I can pass a pointer to the function as a parameter to some other hand crafted function.
The function used to pass the pointer to the hand crafted part of the system is declared like this (here A is not known):
void passPointer(int, void (*f)(int, int));
My cast and function call looks like:
handCraftedObject->passPointer(17, static_cast<void (A::*)(int, int)> (&A::f) );
My compilation error is:
: no known conversion for argument 2 from 'void (A::*)(int, int)' to 'void (*)(int, int)
I hope this doesn't mean i have to know the class A where the function passing the function pointer is declared. This is not possible in my system.

Member function pointer has different type than function pointer and cannot be converted to it. The simplest way is to use boost/std(C++11) bind and function.
void passPointer(int, const std::function<void(int, int)>&);
than just
handCraftedObject->passPointer
(
17, std::bind(static_cast<void (A::*)(int, int)> (&A::f), std::ref(a_instance),
std::placeholders::_1, std::placeholders::_2)
);
Also you cannot use boost/C++11, you can make function f static, then all will works fine.

Related

Passing in function as an argument in C++ using std::function

I have been trying to pass an interpolation function by reference as an argument to another function but I keep getting the following error:
error: could not convert '&AmrCoreAdv::interp_reta_from_R' from 'double (AmrCoreAdv::*)(double)' to 'std::function<double(double)'
There is a header file called AmrCoreAdv.H where the interpolation function is declared as double interp_reta_from_R(double R) and it is defined in another file. The interpolation function is passed as an argument to the state_rhs function and is called as follows:
state_rhs(i, j, k, rhs_fab, state_fab, eta, dx[0], dx2, deta, eta2, two_over_eta, three_over_eta, e2_over_8pi2, &interp_reta_from_R);
The function state_rhs takes in the following arguments:
state_rhs(int i, int j, int k,
amrex::Array4<amrex::Real> const& rhs_fab,
amrex::Array4<amrex::Real const> const& state_fab,
const amrex::Real eta,
const amrex::Real _dx,
const amrex::Real dx2,
const amrex::Real d_eta,
const amrex::Real eta2,
const amrex::Real two_over_eta,
const amrex::Real three_over_eta,
const amrex::Real e2_over_8pi2,
std::function<double (double)> interp_reta_from_R)
I am relatively new to C++ and am lost as to how to proceed. I have tried using typedef and some other ways of defining the type of the interp_reta_from_R function as an argument in the state_rhs function but to no avail. I would really appreciate some guidance on this. Please let me know if you would require any additional information for debugging this issue. Thank you!
A member function is not like a free function - it has a different type which includes the class, and it can't be called without an instance of the class.
The simplest thing is to pass a lambda function instead, capturing the object that should get its member called.
Assuming that the function is a member of *this, replace the pointer-to-member with
[this](double d) { return interp_reta_from_R(d); }
Pointer to member is not a regular pointer, it needs to come with its object.
Consider the following code:
struct S
{
double f(double);
};
//whatever
S s;
s.f(3.14);
The mental model for the call to f can be sth like the following one (this is just a mental model, it has nothing to do with the standard, calling convention etc.):
f(&s, 3.14); //s address
For that reason, in order to transform a member function into a free function, it's object argument needs to be bound to it.
Modern C++ (C++11 onwards) has two means of doing this: std::bind or lambda expressions. For pre-C++11 one can look-up boost::bind which plays essentially the same role as its std counterpart.
Note that lambdas (since C++11) are somewhat limited when it comes to move-only types, which means one might be stuck with bind; should technical limitations not be the case use whatever suits your needs, taste and code conventions.
Also, note that object might be provided either by value (giving the created function object copy semantics) or reference/address. In the latter case, make sure the functor does not outlive the objects it is supposed to be referring to.
Example:
#include <functional>
struct S
{
double f(double) {return{};}
};
void ff(std::function<double(double)>){}
int main(int, char*[])
{
S s;
ff(std::bind(&S::f, s, std::placeholders::_1)); //bind by value
ff(std::bind(&S::f, &s, std::placeholders::_1)); //bind by address
ff([&s](double x){return s.f(x);}); //lambda with capture by reference
ff([s](double x)mutable{return s.f(x);}); //lambda capturing by value. Note mutable; lambdas by default capture by value as const objects!
}
DEMO: https://godbolt.org/z/M9sGj36jq

Unable to pass function pointer as function param

I would like to pass function pointer as a function parameter.
Here is my code:
void AuthServerOpcodes::ValidateAndSetServerOpcode(ServerOpcode serverOpcode, void(*handlerFunc(std::vector<std::byte> data))) {}
Here is the function I would like to pass as second parameter in ValidateAndSetServerOpcode:
void AuthServerOpcodes::Test(std::vector<std::byte> data) {
std::cout << "all good" << std:end
}
Here is how I try to pass it:
ValidateAndSetServerOpcode(SMSG_LOGIN_REQUEST, &Test);
However this seems to be not the correct way. When I try to do it in that way I get error:
Cannot initialize a parameter of type 'void (*(*)
(std::vector<std::byte>))' with an rvalue of type 'void
(AuthServerOpcodes::*)(std::vector<std::byte>)': different return type
('void (*)' vs 'void')
Why is that and how can I fix it?
Pointers to member must be qualified with the class type, so you need to get the pointer you'll need to use
ValidateAndSetServerOpcode(SMSG_LOGIN_REQUEST, &AuthServerOpcodes::Test);
But it looks like you've tried that in the previous edit, so I guess you've called the function pointer to member incorrectly. You didn't show a minimal, reproducible example so I can't help you more, please create one. Anyway I've created a compiled example on Compiler Explorer
typedef void (AuthServerOpcodes::*HandlerFunc)(std::vector<std::byte> &);
void AuthServerOpcodes::ValidateAndSetServerOpcode(ServerOpcode serverOpcode,
HandlerFunc handlerFunc)
{
std::vector<std::byte> myVector;
(this->*handlerFunc)(myVector); // call the hander
}
void FreeStandingFunction(AuthServerOpcodes& opc,
AuthServerOpcodes::HandlerFunc handlerFunc,
std::vector<std::byte> &data)
{
(opc.*handlerFunc)(data);
}
As you can see the pointer to member must be called with ->* or .* and the whole dereferencing must be wrapped inside () because those operators has lower precedence than the function call operator ()
See also Function pointer to member function
Some off-topic note:
Don't use lines that are too long like that
Don't pass vectors by values unless you really need to preserve the outside value. Always pass by reference with const std::vector<>& (or remove const to modify the outside variable)
Use '\n' instead of std::endl
You can't do that.
There is no function pointer to that function, because it is a member function.
You can instead pass a pointer-to-member-function, or better yet a std::function bound to a lambda that captures the this pointer.
It's just a type mismatch, your function is a method of the AccountManager class,
so it has this signature similar to:
static void Login(AccountManager *this, std::vector<..> data);
You can either detach function from class, change your type definition of handlerFunc or consider different techniques like std::mem_fn or std:bind
https://en.cppreference.com/w/cpp/utility/functional/mem_fn
https://en.cppreference.com/w/cpp/utility/functional/bind

std::bind "no matching function for call"

I am trying to set a delegate for a function and have the 2 following classes to achieve that.
On the bottom is the error I'm getting. How do I handle it?
Class A
typedef void (*SocketEventString) (String);
class SocketIO
{
public:
SocketIO();
void onMessage(SocketEventString _cb);
private:
SocketEventString _onMessage;
};
Class B
class BoardManager
{
public:
BoardManager();
void handleAction(String action);
SocketIO io;
};
//Constructor
BoardManager::BoardManager() {
io.onMessage( std::bind( &BoardManager::handleAction, this, std::placeholders::_1 ) );
}
ERROR
sketch/BoardManager.cpp: In member function 'void BoardManager::initializeSocketIO()':
BoardManager.cpp:68: error: no matching function for call to 'SocketIO::onMessage(std::_Bind_helper<false, void (BoardManager::*)(String), BoardManager* const, const std::_Placeholder<1>&>::type)'
io.onMessage( std::bind( &BoardManager::handleAction, this, std::placeholders::_1 ) );
^
sketch/BoardManager.cpp:68:90: note: candidate is:
In file included from sketch/BoardManager.h:10:0,
from sketch/BoardManager.cpp:8:
sketch/SocketIO.h:25:18: note: void SocketIO::onMessage(SocketEventString)
void onMessage(SocketEventString _cb);
The std::bind function return an object that is not compatible or convertible to a pointer to a non-member function.
Instead use std::function:
using SocketEventString = std::function<void(String)>;
With the definition
typedef void (*SocketEventString) (String);
you say that SocketEventString is a pointer to a non-member function (i.e. a function not a member in a class or struct) that takes one argument of type String and returns no value.
The std::bind function returns an object of an unknown class. That object is not the same a the pointer-type you define SocketEventString to be.
The two types (SocketEventString and the object returned by std::bind) are not compatible. You can not convert from one of the types to the other.
The compiler tell you this, because it tries to find a function SocketIO::onMessage which takes the type of the object returned by std::bind and don't find any such overload.
Instead of the SocketEventString type you have defined, you need to use type that is compatible with the object returned by std::bind. That's what I have shown above in my answer, defined SocketEventString to be a different type, a type that is compatible with the type returned by std::bind.
Firstly, you can't use a C function pointer for a C++ function binding like that. Essentially, when you use bind it captures some variables to be used in the function call (such as this), so you need to use std::function which handles capturing variables if you want to bind a member function (because member functions at the very least need the this pointer captured). Also, in my opinion, std::bind is fairly ugly, and I recommend getting familiar the new C++ lambdas.
BoardManager::BoardManager() {
io.onMessage( [&]( String action ) {
handleAction( action );
});
}

What does T::* signify in the declaration of a function parameter list?

I declare a particular keyboard callback function as this inside my code:
void keyboardEventCallback(const pcl::visualization::KeyboardEvent &event, void* viewer_void, void* widget_void);
The keyboard event is the actual event passed to the callback function, the viewer_void parameter is a pointer to a PCLVisualizer class that generates a window for rendering, and widget_void is a pointer to a widget that interfaces with Qt.
In the documentation for pcl, a registration function passes the arguments for registering the keyboard function like
boost::signals2::connection registerKeyboardCallback(void(T::*callback)(const pcl::visualization::KeyboardEvent&, void*), T& instance, void* cookie=nullptr)
So my question is, what is the meaning of T::* inside the registration function declaration, and why am I not allowed to pass this:
m_vis->registerKeyboardCallback(keyboardEventCallback, (void*)&m_vis, (void*)this);
where m_vis is a visualizer, keyboardcallback is the callback, and this is the widget.
Why can I not register like this. This is for the point cloud library.
what is the meaning of T::* inside the registration function declaration
This is the syntax of a pointer to member. Let's take a look at the whole type and name of the parameter:
void(T::*callback)(const pcl::visualization::KeyboardEvent&, void*)
This is the declaration of a variable named callback. It's a pointer to member function. More precisely, it's a pointer to member function of the class T.
If we take the name out of the type, we see things more clearly:
// class name ---v v------- parameters
void(T::*)(const pcl::visualization::KeyboardEvent&, void*)
// ^---- return type
It's in fact, a pointer to function member of the class T that returns void. It's a function that takes strictly two parameters: a const pcl::visualization::KeyboardEvent& and a void*.
why am I not allowed to pass this
It's simple. Look at the type of your function:
using func_type = decltype(keyboardEventCallback);
// hint: the type is: void(*)(const pcl::visualization::KeyboardEvent&, void*, void*)
Let's compare the two types side by side:
void(*)(const pcl::visualization::KeyboardEvent&, void*, void*)
void(T::*)(const pcl::visualization::KeyboardEvent&, void*)
First, your function is not a member function, it's a plain function pointer. It's not the same type. Then, you got three arguments, as the type of the parameter only ask for two. This is different.
Now, how can you fix this??
You could use a lambda:
auto myCallback = [](const pcl::visualization::KeyboardEvent& e, void* c) { /* ... */ }
using lambdaType = decltype(myCallback);
// Be careful here, we don't want our lambda to go out of scope when it is called.
m_vis->registerKeyboardCallback(&lambdaType::operator(), myCallback, this);
Or even simpler: just define keyboardEventCallback inside your class, and send it:
// don't forget: keyboardEventCallback must receive the same parameter as asked.
m_vis->registerKeyboardCallback(&MyClass::keyboardEventCallback, *this, this);
This is the syntax for member functions.
Example:
class A{
int giveMe5();
};
&A::giveMe5; // will be of type int(A::*)()
Why does the type differ from free functions and static member functions ?
Because member functions have an implicit parameter that points to the object on which the function gets called.
https://isocpp.org/wiki/faq/pointers-to-members#fnptr-vs-memfnptr-types
says:
The type of this function is different depending on whether it is an ordinary function or a non-static member function of some class:
- Its type is int (*)(char,float) if an ordinary function
- Its type is int (Fred::*)(char,float) if a non-static member function of class Fred

C++ Bind Return Type Template Arguments

I have the following piece of code:
#include <functional>
template <typename T>
class TD; // For displaying type
void f(int, int, int) { }
int main() {
auto g = std::bind(f, std::placeholders::_1, 2, 2);
TD<decltype(g)> td1;
return 0;
}
In this code TD is a template trick for showing its template argument passed via decltype.
Output of the compiler follows (compiled in C++14 mode):
prog.cpp: In function 'int main()':
prog.cpp:10:18: error: aggregate 'TD<std::_Bind<void (*(std::_Placeholder<1>, int, int))(int, int, int)> > td1' has incomplete type and cannot be defined
TD<decltype(g)> td1;
^
Well, incomplete type error is of course excepted. But what makes me curious in this error message is std::_Bind<void (*(std::_Placeholder<1>, int, int))(int, int, int)>. I can comprehend that std::_Bind is a proxy class which defines operator() and makes our purpose possible. But its template argument void (*(std::_Placeholder<1>, int, int))(int, int, int) made me woow! How should I interpret it? Does it have any usefulness in user-land code? How can I create my own classes making use of this declaration?
void (*(std::_Placeholder<1>, int, int))(int, int, int)
This declares an unnamed function taking three parameters (std::_Placeholder<1>, int and int) and returning a pointer to a function that takes three ints and returns void.
Let's simplify a little. First consider a simple function declaration:
void f(int)
Now, in parameter declarations (of functions or templates) you can omit the name and you get
void (int)
which, if used in a parameter list of a function declaration, would be equivalent to a function pointer void(*)(int).
A function that returns a function pointer is declared like this:
void (*f(int))(int);
// ^ ^ <- this pair of parentheses changes
// the order in which the declaration is parsed.
// Without it, the return type would be `void*`
// and you'd get a syntax error
Now you can remove the name f and you basically get the same thing that you were asking about.
Its uses? Apparently it's useful when implementing std::bind :) I can't think of anything else right now...
C++11 marked the advent of function which made defining function pointers far easier:
Instances of std::function can store, copy, and invoke any Callable target -- functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.
So for example let's say that you needed to take in a function pointer to string foo(int param) { return to_string(param); } in one of your functions. Pre-C++11, your function would need to look like:
void bar(string (*func)(int)) { cout << func(13) << endl; }
Let's go a step further and say you wanted to expand foo to: string foo2(int lhs, int rhs) { return to_string(lhs + rhs); }. But now you want to cram that back into bar. Doing this bar(bind(&foo2, placeholders::_1, 42)); would give you an error like this:
cannot convert 'std::_Bind_helper (*)(int, int), const std::_Placeholder<1>&, int>::type {aka std::_Bind (*(std::_Placeholder<1>, int))(int, int)>}' to 'std::string (*)(int) {aka std::basic_string (*)(int)}' for argument '1' to 'void bar(std::string (*)(int))'
You could get around this error by creating a function that took an implementation specific argument, like: void bar2(_Bind<string (*(_Placeholder<1>, int))(int, int)> func) { cout << func(13) << endl; } which could successfully be called with: bar2(bind(&foo2, placeholders::_1, 42));. The reason that this is implementation specific is that the types: _Bind and _Placeholder are non-standard. In fact the return of bind is:
A function object of unspecified type T
Which brings us to function. If you weren't already turned off by the syntax the limitations of a function pointer, you'll need to take a function parameter to accept an object created by bind. Let's make a new bar using function:
void bar3(function<string(int)> func) { cout << func(13) << endl; }
This is capable of accepting both the traditional function pointer and the bind functor. Additionally it can handle lambdas, so you can do this: bar3([](int param) { return to_string(param); });
I've created a live example so you can play around with this some hopefully the benefits of the function object are clear.