Holding function in variable and changing it dynamically

I need a variable that will just hold a function that I can change in the middle of the application, even to different function type with different amount of parameters ... is this even possible?

at the moment I have this

1
2
3
4
5
6
7
8
9
struct REPLY
{
	string *sReply;
	function<int()> special = [](){return 0;};
	REPLY()
	{
		sReply = NULL;
	}
}reply;


in the middle of app I change special to

reply.special = test;

where test

1
2
3
4
5
int test()
{
	MessageBox(NULL, NULL, NULL, NULL);
	return 0;
}


and then change it back to blank function returning 0 after calling it

1
2
(reply.special)();
reply.special = [](){return 0;};


this works fine (there is no reason why it should not, right?)

now, if I want to have another function, let's say

1
2
3
4
void test2(string str)
{
	MessageBox(NULL, str.c_str(), NULL, NULL);
}


how do I point this one to the variable special, when I want to call it like that (or something similar)

(reply.special)("test string");

is this even possible? if so, how? i tried to create function pointer (didnt compile at all) or use template (neither did this) and I have no idea how to do this as I discovered functional lib just a while ago

thanks!
Last edited on
boost::any might be able to do it
I forget that too sometimes; the object you want is "std::function" and it isn't in the 'functional' header, it's exposed under 'utilities': http://en.cppreference.com/w/cpp/utility/functional/function

Function pointers are another valid solution. Although it's one that belongs more in a C environment then a C++ one. You should still make a mental note to learn how to use those later.
The problem here is what happens when you try to call the function with mismatched parameters?

1
2
3
4
5
6
7
reply.special();  // works if special == test
reply.special("test"); // works if special == test2

// but....

reply.special(); // what if special == test2?  What do you want to happen?
reply.special("test"); // what if special == test?  What do you want to happen? 
@LBT I'll check that

@Computergeek actually, function (which im using) IS from functional header

@Disch well that too, but since I can't even place test2 function (since it's void, while variable is as "int") into "special", I can't even call it - any solution for this?
@Disch well that too, but since I can't even place test2 function (since it's void, while variable is as "int") into "special", I can't even call it - any solution for this?



Well what do you want the solution to be? I mean... what is the desired behavior here?

If you call reply.special() with the expectation that it is going to return an int... yet it is calling a function that returns void .... what do you expect it to return?

 
if( reply.special() == MB_OK )  // what do you expect this to do if special() is calling a function that returns void? 


There are solutions to this problem... but you have to know what you want first.
Last edited on
well I have reply struct that holds a pointer to the string (that will receive response from the server) AND will run the specific function after that - where the type and parameters for the function are not known untill it's "stored" in a variable

so something like this (this is just a made-up code, please don't tell me something like this wont work as I know it wont and it's just to show you what I want)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//functions
int test()
{
	return 0;
}
int test2(int a, int b)
{
	return a+b;
}
void test3(string str)
{
	MessageBox(NULL, str.c_str(), NULL, NULL);
}

//blank function variable that doesn't have type nor parameters
function<()> special;

//store test under special and call it
special = (int)test;
(special)(); //returns 0

//store test3 with "hello" as parameter and call it
special = (void)test3("hello");
(special)(); // displays message box with "hello"

//store test3 with 1 (not known atm) parameter and call it
special = (void)test3;
(special)("hello again"); // displays message box with "hello again"

//store test2 with 1 known and 1 unknown parameter and call it
special = (int)test2(NULL, 5);
(special)(3); //(3+5) 
Last edited on
See? There I go doing it again. There shouldn't be a problem then, just overload the call. You don't even need that object to do this. Also, don't change your return types around.
I guess what's causing my confusion is that I don't understand why you need to put all these different types of functions into one object.

To reiterate my earlier point:

1
2
3
4
5
special = (int)test2(NULL, 5); // say you can do this
special(3);  // and let's say this even works as you expect

special("hello again"); // <- but then... what do you expect to happen when you do this?
  // will the program crash? 


This is the pitfall you have to overcome. Either this will never happen (in which case... 'special' does not need to be a single all-encompassing object and can be split across varying types of functions)... or you will need to handle this condition appropriately.



Little Bobby Tables might be right... boost::any might be the solution here... as it will allow you to put any type into a single container. But you will need to "cast" out the specific type before you are able to use it, which makes it clunky, error prone, and difficult to use (I really dislike boost::any).

My recommendation at this point is to reconsider your design. You're trying to do something that doesn't really make a lot of sense to me. Or maybe I'm just not understanding the bigger picture here.
okay, let's say I won't call the function with "unknown" parameter, e.g. I will always fully do this

1
2
3
4
5
6
7
8
9
10
special = (void)test3("hello");
special();


int my_a = 2;
int my_b = 5;
special = (int)test2(my_a, my_b);
//totally different part of the code, not even the same function, but my_a and my_b are global
my_b = 8;
special(); // should return 10 


is this possible?

also I absolutely dont understand what
'special' does not need to be a single all-encompassing object and can be split across varying types of functions
means

edit: edited code example to be more precise
Last edited on
What you want is run of the mill overloading in which case you want a separate declaration to handle each use case. You might also use Templates with specialized cases but that would be as much if not more work then simple overloading. That way you are not "hot swapping" the member function, you are deciding which version of "special()" to call based on the parameters you pass to it. Anything else is just poor design practice.
Here's the thing, mekkatorqu... every function has to have a signature. std::function allows you to bind functions with slightly different signatures so that they could all be called with the same signature.

The problem is.... you are trying to call with multiple different signatures... which is very easy to break.

Even without the parameter issue, there's the return type issue. Again, reiterating a point I made earlier:

1
2
3
4
5
6
7
8
special = (int)test2(my_a, my_b); // assuming this works
if(special() == 5) { /*...*/ }  // assuming this works

// so we've established that special() returns an int... so...

special = (void)test3("hello");  // even assuming this works...
if(special() == 5) { /*...*/ } // what would this do?  If test3 doesn't return anything...
  // then what does this call to special() return?  It doesn't make any sense logically. 


What do you want to happen here? Should special just return 0 by default?


This reeks of poor design. boost::any sounds like the only thing that's close to what you want... but again I don't recommend it. I recommend you rethink whatever it is you're trying to do (what are you trying to do? Like... the big picture... I understand the immediate problem you're asking about... but I don't understand why you think you need to do it. What is all this for?)

also I absolutely dont understand what [my post] means


You have one object: 'special'. You are trying to treat it as a swiss army knife: One object for everything you need.

This is almost never a good design decision. Aside from having to tackle problems like the one you're describing, it makes the code error prone. Like the points I keep mentioning... even if the syntax allowed what you want to do... it would be very easy to "break" and do something unexpected/undefined.

Rather than trying to cram everything into one object, split it up across several objects.



But again maybe a big picture view would help. I might be able to recommend a better design idea.
Last edited on
> well I have reply struct that holds a pointer to the string (that will receive response from the server)
> AND will run the specific function after that -
> where the type and parameters for the function are not known untill it's "stored" in a variable
> okay, let's say I won't call the function with "unknown" parameter

What you are looking for is probably std::bind()
http://en.cppreference.com/w/cpp/utility/functional/bind

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <string>
#include <functional>

struct reply
{
    std::string msg = "message from server" ;
    std::function< int( std::string ) > special = [](std::string) { std::cout << "do nothing\n" ; return 0; };

    template < typename CALLABLE, typename... ARGS > void rebind( CALLABLE&& fn, ARGS&&... args )
    { special = std::bind( std::forward<CALLABLE>(fn), std::placeholders::_1, std::forward<ARGS>(args)... ) ; }

    int do_callback() { return special(msg) ; }
};

int foo( std::string msg, int a, int b )
{ std::cout << "foo(" << msg << ',' << a << ',' << b << ")\n" ; return a+b ; }

struct bar
{
    long operator() ( const std::string& msg, const char* prefix ) const
    { std::cout << "bar - " << prefix << " '" << msg << "'\n" ; return 23L ; }
};

int main()
{
    reply r ;
    r.do_callback() ; // do nothing

    const auto fn1 = [] ( std::string str ) { std::cout << str << '\n' ; return 0 ; } ;
    r.special = fn1 ;
    r.do_callback() ; // message from server

    r.special = std::bind( foo, std::placeholders::_1, 22, 87 ) ;
    r.do_callback() ; // foo(message from server,22,87)

    r.rebind( foo, 999, 1000 ) ;
    r.do_callback() ; // foo(message from server,999,1000)

    r.rebind( bar(), "the mesage is:" ) ;
    r.do_callback() ; // bar - the mesage is: 'message from server'
}

http://coliru.stacked-crooked.com/a/c661fd1c4a403c98
Topic archived. No new replies allowed.