I got an array of functions to be called later as callbacks:
std::vector<std::function<void(void*)>> callbacks;
I do need to insert different kind of functions to this vector, that's why I choose void* to be the argument.
In one of these functions I needed an int, so I did like that:
void MyObject::MyTestCb(void* params) {
int i = *(int*)params;
...
}
...
callbacks.push_back(std::bind(&MyObject::MyTestCb, this, std::placeholders::_1));
When I call those callbacks, first I tried like this:
int index = 73;
void* params = (void*)&index;
callbacks[x](params);
But sometimes I wasn't received the value in the callback function! Most of the time were obtaining zero. May it is related due to being on a 64 bits machine?
Anyway, I tried this way then:
void* params = new int(73);
callbacks[x](params);
delete params;
And after some testing I didn't find any problem at all. However, is this last way the correct way to do it? Should it support any type as argument?
Related
(Title edited to clarify intent.
Original Title: "Can I heap-allocate a va_list to use it later?")
I'm trying to develop a scripting system for my game that allows me to look at all functions which will be called on a future frame and what arguments they will take. Since the args these functions take aren't all the same, I figured the best approach would be to make a struct containing an unwrapper function that takes a va_list, and a va_list to be passed to it. Each unwrapper function just takes the va_list, separates it back into multiple variables, and passes it to a corresponding real function. Then each script has a queue of those structs to be executed on a given frame.
Here's the script class:
class MoveScript {
public:
MoveScript();
MoveScript(std::string name, std::function<void()> move_script);
void activate(); //Clear the ScriptFrame queue, then call move_script()
void execute(float frame); //Checks if the front ScriptFrame is set to this frame. If it is, then call its execute function and remove it from the queue
std::string name;
std::queue<ScriptFrame> frames;
private:
std::function<void()> move_script{ []() {} }; //Runs whenever a new script is activated, populates the ScriptFrame queue
};
Here's the ScriptFrame class:
class ScriptFrame {
public:
ScriptFrame();
ScriptFrame(float frame);
void execute(); //Executes each function_call in the queue with its corresponding function_arg
float frame;
std::queue<std::function<void(ScriptArg)>> function_calls;
std::queue<ScriptArg> function_args;
};
Here's a ScriptArg:
struct ScriptArg {
ScriptArg();
ScriptArg(int num_args, std::va_list va);
void destroy(); //Call va_end() so I don't have to do it within the unwrapper funcs
int num_args;
std::va_list va;
};
And here's an example of all of this in practice
script("wait", [this]() {
execute_frame(0, [this]() {
push_function(&BattleObject::SET_RATE, 1, 0.5);
});
});
void BattleObject::SET_RATE(ScriptArg args) {
UNWRAP(rate, float);
set_rate(rate);
}
Where script initializes a MoveScript and adds it to a table, execute_frame creates a new ScriptFrame to execute on the given frame, push_function pushes the unwrapper function and a va_list generated by the args to the ScriptFrame's respective queues, and UNWRAP is a macro that expands to float rate = va_arg(args.va, float);
As I’m sure you can already tell, this code doesn’t work because of how a va_list becomes invalid after the function which called va_start returns. I found another question about it but couldn’t find any suggestions that I figured could work. I’ve seen stuff about storing a void* instead of va_list and getting the args directly within push_function, but since the args passed can be of different types, I don’t think there’s any way for me to safely use va_arg at that point. So I was wondering, if I heap-allocate the va_list, will that allow me to store it properly, or does it become invalidated as soon as the function which takes the ellipsis goes out of scope? If it does, can I possibly store the ellipsis directly instead of a va_list, then create a va_list in the unwrapper function? Or just generally if there’s a better way to accomplish my goal, what would that be? Let me know if there’s any other info I should provide.
Thanks!
Update: I tried tuples to store the data as a few answers suggested, but that didn't work because I needed to be able to properly index them while the function was still being wrapped, at which point the number and types of args were still unknown. Due to how templates work, I couldn't find a way to store the entire tuple in the ScriptArg struct either (Note: It's entirely possible that all of this was possible to work around and I just couldn't figure it out, but either way I found a way to handle it without using tuples which works for my purposes).
In any case, I managed to accomplish what I was looking for using a queue of std::any instead of a va_list, and populating the queue with all of the variadic arguments the function took. Handling the variadic args using a tuple still didn't seem to work, but as it turns out, I could just use a vector instead. Here's what the full process looks like.
ScriptArg declaration:
struct ScriptArg {
ScriptArg();
ScriptArg(int num_args, std::queue<std::any> args);
std::any get_arg(); //Get the argument at the front of the queue, pop it and return the argument
void pop();
int num_args;
std::queue<std::any> args;
};
The UNWRAP macros:
//Declares a variable of the given type and extracts its value from the queue
#define UNWRAP(var_name, type) type var_name = std::any_cast<type>(args.get_arg());
//Same as the above, but for variables that were already declared
#define UNWRAP_NO_DECL(var_name, type) var_name = std::any_cast<type>(args.get_arg());
Wrapping a member function:
template<typename ...T>
void push_function(void (BattleObject::* function)(ScriptArg), T... args) {
std::queue<std::any> queue = extract_variadic_to_queue(args...);
ScriptArg sa(sizeof...(args), queue);
active_script_frame.function_calls.push(std::bind(function, this, std::placeholders::_1)); //I believe I could also just bind the arguments directly instead of putting a placeholder here, but since I need to store the arguments separately for other reasons, this is fine.
active_script_frame.function_args.push(sa);
}
template<typename ...T>
std::queue<std::any> extract_variadic_to_queue_impl(const T&... args) {
std::vector<std::any> vec = { args... };
std::queue<std::any> ret;
for (int i = 0, max = vec.size(); i < max; i++) {
ret.push(vec[i]);
}
return ret;
}
template<typename ...T>
std::queue<std::any> extract_variadic_to_queue(T... args) {
return extract_variadic_to_queue_impl(std::any(args)...);
}
And besides the fact that I need to unwrap the float as a double due to std::any's type promotion, the unwrapping function itself looks exactly the same:
void BattleObject::SET_RATE(ScriptArg args) {
UNWRAP(rate, double);
set_rate(rate);
}
I'm still not sure if there's a more efficient way to handle this, but it's overall the simplest method I could find for storing future function arguments without needing to know their quantities and type until they were actually called, which was my end goal. Sorry for not making that more clear in the initial question, but I appreciate you all steering me in the right direction and away from va_lists. Thanks!
So I wanted to challenge myself by writing a small threadpool in C++, and I wanted to try to mimic the easy to use way that std::thread work with, that you can just create a thread and as parameters send a function and parameters for that function, compared to something like pthreads which force you to have a void* as the only indata for the function.
So far I have been able to use templates and parameter packs to create a function that can take another function and parameters for it and execute it, but I can't find a way to store them so that I can execute them at a later time (when there is a free thread in the threadpool). I have tried using both std::function together with std::tuple, and std::bind, but since I don't know exactly what types I am dealing with I can't find a way to store the function and the parameters so that I can use them later on in another part of my code, since at that point I no longer know what types everything is of. Down below is some code I have been messing around with that might help show how I mean.
template<typename Function, typename... Arguments>
void TestFunction(Function func, Arguments... parameters)
{
std::function<std::result_of<Function(Arguments...)>::type(Arguments...)>* tempFunc;
tempFunc = new std::function<std::result_of<Function(Arguments...)>::type(Arguments...)>(func);
void* funcPtr = tempFunc;
std::tuple<Arguments...>* tempTuple;
tempTuple = new std::tuple<Arguments...>(parameters...);
void* tuplePtr = tempTuple;
//func(parameters...);
(Arguments...)>*)funcPtr, *(std::tuple<Arguments...>*)tuplePtr);
auto bindTest = std::bind(func, parameters...);
bindTest();
void* bindPtr = &bindTest;
}
int main()
{
TestFunction(std::printf, "%d, %d, %d\n", 3, 2, 1);
getchar();
return 0;
}
It might be that it's not possible to do what I want to do, and in that case I guess I'll just have to switch to an approach more like pthreads. But if anyone knows a work around I would be grateful.
The key thing is that you can store the return type of std::bind in a std::function. Because std::bind returns an object that is callable. You should then be able to store the std::function instance depending on how you want to handle the return type.
template<typename Function, typename... Arguments>
void TestFunction(Function func, Arguments... parameters)
{
using Ret = typename std::result_of<Function>::type;
std::function<Ret()> val{std::bind(func, parameters...)};
}
If you do this when you first recive the function you no longer have to think about the arguments type, and only the return type. How you handle the return type will depend on the usecase of storing the function. One simple approach is to require that Function is a void function, which may make sense if there is no way to pass the value back to the consumer of the API.
Condition
I use a framework that has an custom type as bellow:
typedef log (*CustomType) (
int timeStamp,
const char* data,
int dataSize,
void* userData,
int dataType,
int viewId
)
and MyClass init method as bellow:
MyClass_Init (void **output, CustomType video, CustomType audio, void* userData)
Question
I used init method like bellow but always receive error (error content is not displayed because i use a framework). pls point me what is missed.
CustomType videoInput;
CustomType audioInput;
void *output = malloc(sizeof(void*);
void *userData = malloc(sizeof(void*));
long result = MyClass_Init(&output, videoInput, audioInput, userData);
A number of things wrong with this code:
You can't intermix function pointers and method pointers. What it boils down to is that the this for a method has to be included in the method call signature. Since the function pointer doesn't include the this pointer (it is a function, not a method pointer), the two can not match.
Most C-based API includes some sort of reference value (most frameworks call those refCon, context or userData), so what you can do is create an adapter function that calls your method. The userData parameter in your CustomType parameter list looks like it is one of those (consult the docs to be sure).
You can probably provide a userData wherever you set MyClass_Init as your callback now. So, if that function to provide a callback to the library was called set_callback( MyCustomType callback, void* userData ), do something like
MyClass *obj = new MyClass; // Or however you create your object
set_callback( MyClassCallbackAdapterFunction, obj );
with an adapter function like:
log MyClassCallbackAdapterFunction( int timeStamp, const char* data, int dataSize, void* userData, int dataType, int viewId )
{
MyClass *myThis = (MyClass*) userData;
// Here you can now call myThis->MyClass_Init( ... ) however you want to.
}
The malloc( sizeof(void*) ) statements look like you're misunderstanding return parameters (also called "side effects" by some teachers). I don't have the docs to whatever API/library you're using, but I'm pretty certain you're supposed to not just pass in buffers the size of a pointer. Either you'd just provide a pointer on the stack in which a buffer will be returned, or you provide a whole buffer (e.g. an array) and its size, and that is where the callback will write to or so.
I have a Mysql table that I am using as a list of different calculations that needs to be done.
Each line in the table has a column of type INT that has the number of the function that needs to be called.
e.g. line 6, data, (function) 1.
I read all the lines one by one and I need to call the relevant functions for each line.
What is the best way to construct it in C++?
should I have another function that returns the pointer of the functions that needs to be called ?
Are there other recommended solutions?
Thanks
It depends on the type of the function (input/outputs) but assuming they are all the same, you can make an array of function pointers. For example:
std::vector<void(*)(int)> MyArray;
Will declare an array of function pointers returning void and taking one int as parameter. Then you can put the functions you want in it and when you want to call them you can use MyArray[i]
If the actual type for the function pointer is long and hard to type, you can use decltype(MyFunction) instead. This requires C++11 though.
Using function pointers may work may work but I would rather make use of something like Strategy pattern.
class DataProcessor {
public:
virtual void process(Data& data) = 0;
// some other things like dtors etc
}
For each type of "function" you can create its corresponding DataProcessor.
To ease lookup, you may make use of a factory, or simply a std::map<int, DataProcessor> (instead of using int as key, will you consider using an enum?), or even a vector/array of DataProcessor.
As a suggestion, this is another way:
//Create only a function and make a switch statement in it:
void myfunction (std::pair<int,int> aRow) { // function:
int result;
int data = aRow.second;
int function_id = aRow.second;
switch(function_id){
case 1:{
//Funcion with any signature
break;
}
case 2:{
//Funcion with another signature
break;
}
//and so on...
}
//do something with the result...
}
int main () {
//Fetch your mysql data here:
std::vector<std::pair<int, int> > myMySQLdata;
for_each (myMySQLdata.begin(), myMySQLdata.end(), myfunction);
}
Say that you define a callback function as such:
typedef std::function<void(float)> Callback;
And you have a function as such:
void ImAFunction(float a)
{
//Do something with a
}
Is there a way to be able to store a function without an argument then pass one to it at a later time?
Such as this:
//Define the Callback storage
Callback storage;
storage = std::bind(ImAFunction, this);
//Do some things
storage(5);
This wont work which I explain with some of my real code below.
I can get close to what I wan't if I bind the value in with the std::bind function. Such as:
//Change
//storage = std::bind(ImAFunction, this);
storage = std::bind(ImAFunction, this, 5.0); //5.0 is a float passed
This works but when I go to pass a value through the function the outcome is whatever I set it to before:
storage(100); //Output is still 5
I am basing the fact that I think this is possible on this article.
http://www.cprogramming.com/tutorial/function-pointers.html
It doesn't use the function or bind functions but it does pass pointer arguments and performs exactly what I need. The reason I don't just skip the bind function is because I am trying to store the function in a class (private) and I can't store it if it's a template because it's created with the class.
The error produced above comes from this code:
struct BindInfo {
Callback keyCallback;
int bindType;
bool isDown;
bool held;
std::string name;
};
template <class T1>
void bindEvent(int bindType, T1* keydownObj, void(T1::*keydownF)(float), std::string name)
{
BindInfo newKeyInfo = { std::bind(keydownF, keydownObj), bindType, false, false, name };
inputBindings.insert(std::pair<int, BindInfo>(BIND_NULL, newKeyInfo));
};
The error is:
No viable conversion from '__bind<void(Main::*&)(float), Main *&>' to 'Callback' (aka 'function<void (float)>'
Is this possible? Thanks in advance.
You can include a placeholder for an unbound argument:
std::bind(&Main::ImAFunction, this, std::placeholders::_1);
If you find that a bit of a mouthful, a lambda might be more readable:
[this](float a){ImAFunction(a);}
It sounds like what you're looking for is a function pointer. While I don't have a lot of experience using them in C++ I have used them in C so: Yes, it is possible. Perhaps something like this:
void (*IAmAFunctionPointer)(float) = &IAmAFunction;
The best way to think about that line is, that IAmAFunctionPointer is a pointer (hence the *), it returns a void, and takes a float. Then later:
float a = 5;
IAmAFunctionPointer(a);
You could even design it so that the callback function is passed into the method (I assume this is what you're looking for).
void DoStuffThenCallback(float a, void (*callback)(float))
{
//DoStuff
callback(a);
}
further reading: http://www.cprogramming.com/tutorial/function-pointers.html