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 );
});
}
Related
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
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
I have a vector of shared_ptr, I want to combine boost shared_ptr and bind together.
My question is very similar to this, except that instead of "&MyClass::ReferenceFn" I would like to call "&Element::Fn".
Here is a similar piece of code:
typedef boost::shared_ptr< Vertex > vertex_ptr;
std::set<vertex_ptr> vertices;
void B::convert()
{
...
if( std::find_if(boost::make_indirect_iterator(vertices.begin()),
boost::make_indirect_iterator(vertices.end() ), boost::bind( &Vertex::id, boost::ref(*this), _1 ) == (*it)->id() ) == vertices.end() )
}
here is the error:
no matching function for call to ‘bind(<unresolved overloaded function type>, const boost::reference_wrapper<B>, boost::arg<1>&)’
NOTE: I am limited to use the C++03.
To call a member function for each object stored in a collection, you need to use a placeholder as the first bound argument of the boost::bind:
boost::bind(&Vertex::id, _1) == (*it)->id())
// ~^~
This way, each argument a, will be bound to a member function pointer, and called as (a.*&Vertex::id)().
However, seeing that the error message says unresolved overloaded function type, it draws a conclusion that your class Vertex can have multiple overloads of member function id. As such, the compiler is unable to tell which one it should pass as the argument of boost::bind. To solve this, use an explicit cast to a member function pointer (the asterisk after colon indicates it's a pointer to a member):
boost::bind(static_cast<int(Vertex::*)()const>(&Vertex::id), _1) == (*it)->id())
// ~~~~~~~~~~~~~~~~~~~~^
In the case class Vertex has multiple overloads, say:
int id() const { return 0; }
void id(int i) { }
you will use the first one for binding.
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.
I'm trying to write predicate function for use with STL algorithms. I see that they are two ways to define a predicate:
(1) Use a simple function as below:
bool isEven(unsigned int i) { return (i % 2 == 0); }
std::find_if(itBegin, itEnd, isEven);
(2) Use the operator() function as below:
class checker {
public:
bool operator()(unsigned int i) { return (i % 2 == 0); }
};
std::find_if(itBegin, itEnd, checker);
I have more use for the second type as I usually would like to create a predicate object with some members in it and use them in the algorithm. When I add the same isEven function inside checker and use it as a predicate, I get an error:
3. Syntax which gives error:
class checker {
public:
bool isEven(unsigned int i)
{ return (i%2 == 0); }
};
checker c;
std::find_if(itBegin, itEnd, c.isEven);
Calling c.isEven gives an error during compilation saying undefined reference to some function. Can someone explain why 3. is giving error? Also, I would appreciate any pointers to read about predicate and iterator basics.
A pointer to a member function requires an instance to be called on, and you are passing only the member function pointer to std::find_if (actually your syntax is incorrect, so it doesn't work at all; the correct syntax is std::find_if(itBegin, itEnd, &checker::isEven) which then still doesn't work for the reasons I gave).
The find_if function expects to be able to call the function using a single parameter (the object to test), but it actually needs two to call a member function: the instance this pointer and the object to compare.
Overloading operator() allows you to pass both the instance and the function object at the same time, because they're now the same thing. With a member function pointer you must pass two pieces of information to a function that expects only one.
There is a way to do this using std::bind (which requires the <functional> header):
checker c;
std::find_if(itBegin, itEnd, std::bind(&checker::isEven, &c, std::placeholders::_1));
If your compiler doesn't support std::bind, you can also use boost::bind for this. Though there's no real advantage to doing this over just overloading operator().
To elaborate a bit more, std::find_if expects a function pointer matching the signature bool (*pred)(unsigned int) or something that behaves that way. It doesn't actually need to be a function pointer, because the type of the predicate is bound by the template. Anything that behaves like a bool (*pred)(unsigned int) is acceptable, which is why functors work: they can be called with a single parameter and return a bool.
As others have pointed out, the type of checker::isEven is bool (checker::*pred)(unsigned int) which doesn't behave like the original function pointer, because it needs an instance of checker to be called on.
A pointer to a member function can be conceptually considered as a regular function pointer that takes an additional argument, the this pointer (e.g. bool (*pred)(checker*, unsigned int)). You can actually generate a wrapper that can be called that way using std::mem_fn(&checker::isEven) (also from <functional>). That still doesn't help you, because now you have a function object that must be called with two parameters rather than only one, which std::find_if still doesn't like.
Using std::bind treats the pointer to a member function as if it was a function taking the this pointer as its first argument. The arguments passed to std::bind specify that the first argument should always be &c, and the second argument should bind to the first argument of the newly returned function object. This function object is a wrapper that can be called with one argument, and can therefore be used with std::find_if.
Although the return type of std::bind is unspecified, you can convert it to a std::function<bool(unsigned int)> (in this particular case) if you need to refer to the bound function object explicitly rather than passing it straight to another function like I did in my example.
I guess it's because the type of c.isEven() is,
bool (checker::*)(unsigned int) // member function of class
which may not be expected by find_if(). std::find_if should be expecting either a function pointer (bool (*)(unsigned int)) or a function object.
Edit: Another constraint: A non-static member function pointer must be called by the class object. In your case, even if you succeed to pass the member function then still find_if() will not have any information about any checker object; so it doesn't make sense to have find_if() overloaded for accepting a member function pointer argument.
Note: In general c.isEven is not the right way to pass member function pointer; it should be passed as, &checker::isEven.
checker::isEven is not a function; it is a member function. And you cannot call a non-static member function without a reference to a checker object. So you can't just use a member function in any old place that you could pass a function pointer. Member pointers have special syntax that requires more than just () to call.
That's why functors use operator(); this makes the object callable without having to use a member function pointer.
I prefer functors (function objects) because make your program more readable and, more importantly, expressing the intent clearly.
This is my favorite example:
template <typename N>
struct multiplies
{
N operator() (const N& x, const N& y) { return x * y; }
};
vector<int> nums{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// Example accumulate with transparent operator functor
double result = accumulate(cbegin(nums), cend(nums), 1.1, multiplies<>());
Note: In recent years we've got a lambda expression support.
// Same example with lambda expression
double result = accumulate(cbegin(nums), cend(nums), 1.1,
[](double x, double y) { return x * y; });
The example given says you should use the call operator (operator()) whereas in your example you've called your function isEven. Try re-writing it as:
class checker {
public:
bool operator()(unsigned int i)
{ return (i%2 == 0); }
};