I was tackling with this problem and I asked this other question here, but even after I get the result I couldn't get the thing work. And before we start, I used pointers to pass functions before in C but I'm relatively new to C++ and pointers don't pass functions with unknown arguments.
My question is:
How do I get to pass a function to a class without necessarily knowing how many arguments does it take. What should I do if I want to feed the function that I want to bind into the class? Something like:
ac ac1(args_of_the_object, a_function_with_its_arguments)
I got the bind function work in the class initializing list, thanks to anyone who helped,
function<void()> sh = bind(&hard_coded_function_name, argument);
and I can set the argument when creating an object of the class:
class_name(type ar) : argument(ar) {};
You got the point. Thing is, I can not pass the function itself to the class. I tried using this with a slight modification in class initializing list:
class_name cl1(args, bind(&func_i_want, arguments));
But it resulted in stack dump error.
Thanks!
Edit: (It was too long for a comment)
#include <iostream>
#include <cmath>
#include <limits>
#include <vector>
#include <functional>
using namespace std;
void diffuse(float k){
cout << " WP! " << k;
}
class Sphere{
public:
function<void()> sh;
Sphere (function<void()> X) : sh(X) {};
//another try
function<void()> sh;
Sphere (void (*f)(float)) : sh(bind(&f, arg)) {}; // This is not what I want obviously still I tried it and it doesn't work either.
void Shader(){
sh();
}
};
Color trace(vector<Sphere>& objs){
// find a specific instance of the class which is obj in this case
// Basically what I'm trying to do is
// assigning a specific function to each object of the class and calling them with the Shader()
obj.Shader();
// Run the function I assigned to that object, note that it will eventually return a value, but right now I can't even get this to work.
}
int main() {
vector<Sphere> objects;
Sphere sp1(bind(&diffuse, 5));
Sphere sp1(&diffusea); // I used this for second example
objects.push_back(sp1);
trace(objects);
return 0;
}
Here's the whole code if you want to see: LINK
No, you can only store data whose type is known (at compile time).
However, you can pass the function as an argument. Function templates take care of various types.
class Sphere {
public:
template<typename F>
void shade(F&& f);
};
For example
void functionA(int) {}
void functionB(double) {}
Sphere sphere;
sphere.shade(functionA);
sphere.shade(functionB);
Related
I need to pass the object of the class that i'm working on to a function. For me it's hard to explain, so I made a simple example.
I tried using 'this' operator, hoping that it will send 'this' object to the function, but it didn't work. I also tried googling the problem, but I could't find any sensible answers.
#include <iostream>
unsing namespace std;
class apple;
int eatApple(apple & a)
{
a.var1=0;
a.var2=0;
return 0;
}
class apple
{
int var1;
int var2;
void cutApple();
};
void apple::cutApple()
{
var1/=2;
var2/=2;
eatApple(/*HERE I HAVE TO PASS THE OBJECT OF THE CLASS TO THE FUNCTION*/);
}
int main()
{
apple Apple;
Apple.cutApple();
return 0;
}
Note that this code is just a example of the problem. Where i have written in the /* */, that's where i tried the 'this' operator, but i didn't work.
The function header looks like this: int eatApple(apple & a), which means it accepts a reference to apple. this is always a pointer (not a reference), therefore you need to dereference it:
eatApple(*this);
I want to pass a member function as a call-back. The call back is a basic function pointer.
So I have something like:
h file:
void (*pRequestFunc) (int someint) = 0;
void RegisterRequestCallBack(void (*requestFunc) (int someint))
{
pRequestFunc = requestFunc;
}
class A
{
void callBack(int someint);
}
Cpp File:
RegisterRequestCallBack(&A::callBack); // This does not work.
Note I have tried to extract this example from my larger example and cut out all the other stuff - so it might not be perfect.
The problem, as far as I understand, is that member function pointers really (under the hood) have an extra parameter (and instance - i.e. this) and are not compatible with normal function pointers.
the RegisterRequestCallBack() is in reality not my code - and so I can't change that.
So I read that boost::bind can do what I need - and I am hoping c++11 std::bind can do the same - but I could not figure out how to use it to effectively get a standard function pointer from a member function pointer...
I was going for something like:
std::bind(&A::callBack) ... that is about as far as I got, my understanding of the examples online is poor :(
NathanOliver's comment is correct, and your suspicion is mostly correct. Exactly how pointers to member functions work is not specified, but including this as a hidden argument mostly works. You just need a bit of extra work for inheritance and pointers to virtual functions (yes, you can take their address too).
Now, often callbacks include a void* parameter under your control, which you can use to pass a A*. In those cases, you can write a wrapper (static) function that casts the void* back to A* and does the actual call to &A::callback.
That's not the case here. Registration takes a single function, without data. To get this to work in real-life situations, you have to resort to drastic solutions - not portable C++. One such method is to dynamically generate assembly (!). You create - at runtime - the compiled equivalent of
void __trampoline_0x018810000 (int i)
{
A* __this = reinterpret_cast<A*>(0x018810000);
__this->callback(i);
}
As you can see, you have to generate one trampoline for every A* value, and managing lifetimes of these is a major pain.
To be able to bind to a member function you need to do:
std::function<void(int)> function = std::bind(&A::foo, this, std::placeholders::_1);
Or in your case:
RegisterRequestCallBack(std::bind(&A::callback, this, std::placeholders::_1));
But in my opinion the clearest way to achieve this is to use lambda functions. Here you have an example to for doing something similar that could inspire you:
#include <array>
#include <map>
#include <vector>
#include <functional>
#include <iostream>
class TaskManager {
public:
using task_t = std::function<void()>;
void run();
void addTask(task_t task);
private:
std::vector<task_t> _tasks;
};
void TaskManager::run() {
for (auto& task : _tasks) {
task();
}
}
void TaskManager::addTask(task_t task) {
_tasks.push_back(task);
}
class Example {
public:
Example(){
taskManager.addTask([this]() {
task1();
});
taskManager.addTask([this,a=int(4)](){
task2(a);
});
}
TaskManager taskManager;
private:
void task1(){ std::cout << "task1!\n"; }
void task2(int a){ std::cout << "task2 says: " << a << "\n"; }
};
int main() {
Example example;
example.taskManager.run();
}
which outputs:
task1!
task2 says: 4
class f
{
public:
run(std::string method,std::string params)
{
...//call foo1 or foo2 with params by "method"
}
foo1(std::string a);
foo2(std::string a);
}
I'm trying to make a map<std::string,std::function<void(std::string)>> to implement it,but there is a error reported since the non-static member function needs a pointer to an instance.I'm not going to use function pointer like typdef f xxx,I preper to make a map between funcname and function.
Your approach is possible. You just need the correct prototype in std::function's definition.
std::map<std::string, std::function<void(f*, std::string)>> func_map;
The above will of course require that any member function you place here will return void and accept a std::string by value. No other prototypes will be admissible.
You can store the member pointers like this:
func_map["foo1"] = &f::foo1;
And then proceed to call them in run like so:
func_map[func_name](this, arg);
Ideally, func_map should be static. So you'd initialize it like so:
std::map<std::string, std::function<void(f*, std::string)>> f::func_map {
{"foo1", &f::foo1},
{"foo2", &f::foo2},
};
It's also worth-noting that you don't need to use std::function if all you want to store is pointers to members. Those can be stored directly. However, the flip side is that your approach allows for extendabilty!
Any free function which accepts f by pointer and a std::string by-value can be stored in the map as well.
You can solve it using this method:
#include <iostream>
#include <string>
#include <map>
#include <functional>
class f{
public:
std::map<std::string,std::function<void(f&,std::string)>> func_map{
{"foo1",[](auto& obj,std::string params){obj.foo1(params);} },
{"foo2",[](auto& obj,std::string params){obj.foo2(params);} }
}; // make static or accept inputs from outside the class
void run(std::string method,std::string params){
func_map.at(method)(*this,params); // treat exceptions as you want
}
void foo1(std::string a){std::cout << "foo1: " << a;}
void foo2(std::string a){std::cout << "foo2: " << a;}
};
int main(){
f fff;
fff.run("foo1","some_params");
fff.run("foo2","some_params");
}
Online Example
The only way in C++ is to switch on the string
if(method.compare"PrintButton")
classobj.PrintButton(atoi(params.c_str());
Strings are runtime objects, identifiers are compile time objects.
You can go the template route however to achieve much the same thing.
I have a shape class that I initialize from my main program and give the parameters in the constructor.
Shape *cusomShape = new CustomShape(float radius, float origin)
The shape class has some functions such as rollover and more.
When the rollover function inside the shape class is fired, I want to change a certain int value in the main program. This might similar to firing of an event that changes the value when the rollover function is fired, but I am not sure how to do that in C++. If at all, events is the ideal approach here, it would great to see a short example coming.
If using the event is not the correct, what would the ideal way to go about this?
I think what you need is to pass a value by pointer or reference to the function in Shape and then modify it. If the function is called not from main but from somewhere else passing the pointer is the better option you have. First pass the pointer to the class and store it using another method and then each time rollover is called make use of it.
EDIT: example:
class CustomShape {
void storePointer(int* _value) {
value = _value;
}
void rollover() {
.. do stuff
*value++; // for instance
... do stuff
}
int * value;
}
int main() {
int a;
CustomShape cs;
cs.storePointer(&a);
....
cs.rollover();
....
return 0;
}
Pass a reference to the variable in the constructor and save that reference. Change the value when needed.
I would suggest passing a reference to the variable to the member function that needs to change its value. Storing a reference in a class couples the Shape class to the reference. This means that each time you want to use the Shape, without updating the integer, you cannot, since the Shape constructor will expect a reference/pointer to the int as an argument (the Shape class will store the pointer/reference as an attribute). Passing a reference/pointer to the member function promotes Low Coupling.
#include <iostream>
class Shape
{
double shapeValue_;
public:
Shape (double value)
:
shapeValue_(value)
{}
void fireFunction(int& updateMe)
{
updateMe = 123;
}
};
using namespace std;
int main()
{
int update;
cout << update << endl;
Shape s(4.5);
s.fireFunction(update);
cout << update << endl;
return 0;
};
And in this case, you have an option for a main program that doesn't involve shape object calling on fireFunction:
int main()
{
Shape s(4.5);
// Main program that doesn't use fireFunction.
return 0;
};
In this case, if you have member functions changing input arguments, you should take on a style for defining such functions: e.g. make sure that the variable that gets changed by the member function is always the first input argument in its declaration.
If you want complex objects to communicate updates between each other, you can make use of the Observer Pattern.
I have a class Test with a peculiar data structure.
A member of class Test is a std::map where the key is a std::string and the mapped value is a struct defined as follows:
typedef struct {
void (Test::*f) (void) const;
} pmf_t;
Initialization of the map is OK. The problem is when I am trying to call the function pointed. I made up a toy example reproducing the problem. Here it is:
#include <iostream>
#include <map>
using namespace std;
class Test;
typedef void (Test::*F) (void) const;
typedef struct {
F f;
} pmf_t;
class Test
{
public:
Test () {
pmf_t pmf = {
&Test::Func
};
m["key"] = pmf;
}
void Func (void) const {
cout << "test" << endl;
}
void CallFunc (void) {
std::map<std::string, pmf_t>::iterator it = m.begin ();
((*it).second.*f) (); // offending line
}
std::map<std::string, pmf_t> m;
};
int main ()
{
Test t;
t.CallFunc ();
return 0;
}
Thanks in advance,
Jir
The name of the pmf_t type is f, so the first change is to remove the * to get second.f. That gives you a pointer-to-member value. To use a pointer-to-member, you need an instance. The only one you have available of the correct type is this, so use it with the ->* operator:
(this->*it->second.f)();
You need parentheses around the whole thing, or else the compiler thinks you're trying to call it->second.f() (which isn't allowed) and then applying the result to ->*.
The offending line is trying to call a member function without any object to call it on. If the intention is to call it for the this object, I believe the call should look like
( this->* ((*it).second.f) )();
Where this->* is the syntax for dereferencing a pointer-to-member for the current object. ((*it).second.f) is the pointer retrieved from the map, and () is the call operator for actually calling the function.
This is perhaps good as an exercise, but otherwise of limited use.
I think you might want to check out the C++ FAQ on this one. The syntax is apparently pretty tricky to get right (they actually recommend using a macro).
It might be too late for this question but, the seemingly complex synatax can be break down to two simple lines so it looks pretty clear:
void CallFunc (void)
{
pmf_t t = m["key"]; //1>get the data from key
(this->*t.f)(); //2>standard procedure to call pointer to member function
}
try this:
(this->*((*it).second.f)) ();