Variable number of arguments (va_list) with a function callback? - c++

I am working on implementing a function that would execute another function a few seconds in the future, depending upon the user's input. I have a priority queue of a class (which I am calling TimedEvent) that contains a function pointer to the action I want it to execute at the end of the interval. Say for instance that the user wants the program to call a function "xyz" after 3 seconds, they would create a new TimedEvent with the time and the function pointer to xyz and add it to the priority queue (which is sorted by time, with the soonest events happening first).
I have been able to successfully get the priority queue to pop off the top element after the specified time, but am running into a wall here. The functions I want to call could take a variety of different parameters, from ones that take only a single integer to ones that take 3 integers, a string, etc. and also return different values (some ints, some strings, etc.). I have looked into va_lists (which I have no experience with), but this doesn't seem to be the answer, unless I'm missing something.
In summary (the TL;DR version):
I would like to be able to call these functions as "diverse" as these with the same function pointer:
void func1(int a, int b);<br/>
int func2(int a, string b, OtherClass c);
Am I on the right track with a va_list and a function callback? Can this be implemented easily (or at all)?
Thanks!

I'm inferring here that these functions are API calls that you have no control over. I hacked up something that I think does more or less what you're looking for; it's kind of a rough Command pattern.
#include <iostream>
#include <string>
using namespace std;
//these are the various function types you're calling; optional
typedef int (*ifunc)(const int, const int);
typedef string (*sfunc)(const string&);
// these are the API functions you're calling
int func1(const int a, const int b) { return a + b; }
string func2(const string& a) { return a + " world"; }
// your TimedEvent is given one of these
class FuncBase
{
public:
virtual void operator()() = 0;
};
// define a class like this for each function type
class IFuncWrapper : public FuncBase
{
public:
IFuncWrapper(ifunc fp, const int a, const int b)
: fp_(fp), a_(a), b_(b), result_(0) {}
void operator()() {
result_ = fp_(a_, b_);
}
int getResult() { return result_; }
private:
ifunc fp_;
int a_;
int b_;
int result_;
};
class SFuncWrapper : public FuncBase
{
public:
SFuncWrapper(sfunc fp, const string& a)
: fp_(fp), a_(a), result_("") {}
void operator()() {
result_ = fp_(a_);
}
string getResult() { return result_; }
private:
sfunc fp_;
string a_;
string result_;
};
int main(int argc, char* argv[])
{
IFuncWrapper ifw(func1, 1, 2);
FuncBase* ifp = &ifw;
// pass ifp off to your TimedEvent, which eventually does...
(*ifp)();
// and returns.
int sum = ifw.getResult();
cout << sum << endl;
SFuncWrapper sfw(func2, "hello");
FuncBase* sfp = &sfw;
// pass sfp off to your TimedEvent, which eventually does...
(*sfp)();
// and returns.
string cat = sfw.getResult();
cout << cat << endl;
}
If you have a lot of functions returning the same type, you can define a subclass of FuncBase that implements the appropriate GetResult(), and wrappers for those functions can subclass it. Functions returning void would not require a GetResult() in their wrapper class, of course.

I think boost::bind will be useful to you. For your application, you will probably want to bind all arguments when you create the functor, before putting it on the queue (that is, not use any _1 or _2 placeholders). I don't think you need anything as complicated as lambda expressions/abstractions, but it's good to understand what they are.
+1 ceo for the DIY approach. That will work too, but you have to do all the hard work yourself.
If you want to DIY though, I would suggest using templates instead of defining an xfunc and XFuncWrapper for each combination of types (see code below).
Also, I think allowing different return types is going to be pointless -- whatever code is de-queuing and calling the functions is going to be generic. Either it expects the same type of return from each function, or it expects them to be procedures (return void).
template<typename R>
class FuncWrapper0 : public FuncBase
{
public:
typedef R (*func)();
FuncWrapper0(func fp) : fp_(fp) { }
void operator()() { result_ = fp_(); }
R getResult() { return result_; }
private:
func fp_;
R result_;
};
template<typename R, typename P1>
class FuncWrapper1 : public FuncBase
{
public:
typedef R (*func)(const P1 &);
FuncWrapper1(func fp, const P1 &p1) : fp_(fp), p1_(p1) { }
void operator()() { result_ = fp_(p1_); }
R getResult() { return result_; }
private:
func fp_;
P1 p1_;
R result_;
};
template<typename R, typename P1, typename P2>
class FuncWrapper2 : public FuncBase
{
public:
typedef R (*func)(const P1 &, const P2 &);
FuncWrapper2(func fp, const P1 &p1, const P2 &p2)
: fp_(fp), p1_(p1), p2_(p2) { }
void operator()() { result_ = fp_(p1_, p2_); }
R getResult() { return result_; }
private:
func fp_;
P1 p1_;
P2 p2_;
R result_;
};

What you're trying to do is almost impossible to get to work. You might want to consider packing your parameters into something like an std::vector<boost::any> instead.
Variable parameter lists are really the opposite of what you want. A variable parameter list allows a single function to be called from multiple sites, each with a unique set of parameters. What you want is to call multiple functions from a single site, each with a unique set of parameters -- and a variable parameter list just doesn't support that.

c/invoke is a library that lets you construct arbitrary function calls at runtime, but I think that's overkill in this case. It sounds like you should find a way to "normalize" the callback function's signature so that you can call it the same way every time with a list, structure, union or something that allows you to pass different data through the same interface.

Well, there is a real hardcore trick that exploits the fact that in C every function is a pointer and you can cast a pointer to any other pointer. The original code, where I got this from, was written, when compilers didn't gave errors on implicit casts, so it took me a while to figure out that I had to cast the functions. What it does is that it casts the callback function to a function with a variable number of arguments. But at the same time, the invocation function is cast to a function with 10 arguments, of which not all will be supplied. Especially this last step seems tricky, but you've seen it before, where you give the wrong number of arguments to printf and it just compiles. It might even be that this is what va_start/va_end does under the hood. The code is actually for doing a custom operation on any element in the database, but it could be used for your situation as well:
#include <stdio.h>
typedef int (*INTFUNC)(int,...);
typedef int (*MAPFUNCTION)(int [], INTFUNC, ...);
//------------------CALLBACK FUNCTION----------------
static int callbackfunction(int DatabaseRecord,int myArgument,int *MyResult){
if(DatabaseRecord < myArgument){
printf("mapfunction record:%d<%d -> result %d+%d=%d\n",DatabaseRecord,myArgument,*MyResult,DatabaseRecord,*MyResult+DatabaseRecord);
*MyResult+=DatabaseRecord;}
else{
printf("mapfunction record:%d<%d not true\n",DatabaseRecord,myArgument);
}
return 0; // keep looping
}
//------------------INVOCATION FUNCTION---------------
static int MapDatabase(int DataBase[], INTFUNC func, void* a1, void* a2, void* a3, void* a4, void* a5, void* a6, void* a7, void* a8, void* a9)
{
int cnt,end;
int ret = 0;
end = DataBase[0]+1;
for(cnt = 1;cnt<end;++cnt){
if(func(DataBase[cnt], a1, a2, a3, a4, a5, a6, a7, a8, a9)) {
ret = DataBase[cnt];
break;
}
}
return ret;
}
//------------------TEST----------------
void TestDataBase3(void)
{
int DataBase[20];
int cnt;
int RecordMatch;
int Result = 0;
DataBase[0] = 19;
for(cnt = 1;cnt<20;++cnt){
DataBase[cnt] = cnt;}
// here I do the cast to MAPFUNCTION and INTFUNC
RecordMatch = ((MAPFUNCTION)MapDatabase)(DataBase,(INTFUNC)callbackfunction,11,&Result);
printf("TestDataBase3 Result=%d\n",Result);
}
The same functionality can perfectly be written by using va_start/va_end. It might be the more official way of doing things, but I find it less user friendly. Either the callbackfunction needs to decode its arguments or you need to write a switch/case block inside the invocation function for every combination of arguments that the callback function can have. This means that you have to supply the format of the arguments (just like printf does) or you have to require that all arguments are the same and you just supply the number of arguments, but then you still have to write a case for each amount of arguments. Here is an example where the callback function decodes the arguments:
#include <stdio.h>
#include <stdarg.h>
//------------------CALLBACK FUNCTION----------------
static int callbackfunction(int DatabaseRecord,va_list vargs)
{
int myArgument = va_arg(vargs, int); // The callbackfunction is responsible for knowing the argument types
int *MyResult = va_arg(vargs, int*);
if(DatabaseRecord < myArgument){
printf("mapfunction record:%d<%d -> result %d+%d=%d\n",DatabaseRecord,myArgument,*MyResult,DatabaseRecord,*MyResult+DatabaseRecord);
*MyResult+=DatabaseRecord;}
else{
printf("mapfunction record:%d<%d not true\n",DatabaseRecord,myArgument);
}
return 0; // keep looping
}
//------------------INVOCATION FUNCTION---------------
static int MapDatabase(int DataBase[], int (*func)(int,va_list), int numargs, ...)
{
int cnt,end;
int ret = 0;
va_list vargs;
end = DataBase[0]+1;
for(cnt = 1;cnt<end;++cnt){
va_start( vargs, numargs ); // needs to be called from within the loop, because va_arg can't be reset
if(func(DataBase[cnt], vargs)) {
ret = DataBase[cnt];
break;
}
va_end( vargs ); // avoid memory leaks, call va_end
}
return ret;
}
//------------------TEST----------------
void TestDataBase4(void)
{
int DataBase[20];
int cnt;
int RecordMatch;
int Result = 0;
DataBase[0] = 19;
for(cnt = 1;cnt<20;++cnt){
DataBase[cnt] = cnt;}
RecordMatch = MapDatabase(DataBase,callbackfunction,2,11,&Result);
printf("TestDataBase4a Result=%d\n",Result);
Result = 0;
RecordMatch = MapDatabase(DataBase,callbackfunction,0,11,&Result); // As a hack: It even works if you don't supply the number of arguments.
printf("TestDataBase4b Result=%d\n",Result);
}

#Redef, if your compiler optimizes args into registers, it need not push them on the stack unless they are vargs. This means, in your first example, that callbackfunction will be expecting args in registers whilst the caller using INTFUNC (with a vargs decl) pushes them on the stack.
The result will be that the callback doesn't see the args.

Related

C++ best practice - function type alias std::function<T> or T

What is considered to be best or good practice when declaring type aliases for function types in C++ (I know this part of the question is probably subjective)? Either
using FuncType = void(int, int);
or
using FuncType = std::function<void(int, int)>;
Are there benefits of one over the other?
How should I use these types as function arguments (when passing as functor, lambda, member or global function), for example
void foo(FuncType&& func) { ... }
void foo(FuncType func) { ... }
void foo(std::function<FuncType> func) { ... }
EDIT
I know that not all of my examples above are applicable with both #1 and #2 but that is not the point. I want to know which (and why) option is better and how should I pass this type when using it as a function argument.
Specific use case
As it appears to be too broad (which I absolutely understand) I'm going to give more detail about my specific case.
I have a class that holds a vector of functions that I want to call (most likely parallel, but I don't think this matters). In this class I can add functions to the vector at runtime.
For example:
class
Container
{
public:
using FuncType = std::function<void(const SomeComplexDataType&, int, double)>;
inline void addFunction(FuncType func)
{
_funcs.push_back(func);
}
inline void call(const SomeComplexDataType& a, int b, double c)
{
for (auto& func : _funcs)
func(a, b, c);
}
private:
std::vector<FuncType> _funcs{};
};
struct HeavyFunctor
{
// contains some heavy objects
void operator()(const SomeComplexDataType& a, int b, double c)
{
/* Some heavy workload */
}
};
int main()
{
Container c;
c.addFunction([](const SomeComplexDataType& a, int b, double c) { /* do something lightweight */ });
c.addFunction(HeavyFunctor);
c.call(x, y, z);
return 0;
}
How should I define FuncType and the parameter for addFunction and how can I store them in the vector (in a best case scenario, without copying the callables)?
I'd personnaly use:
typedef std::function<void(int,int)> FuncType;
and
void foo(const FuncType &func) { ... }
edit:
Not the best for performance considering comment on this post as it requires virtual dispatch.

Callback an unknown class+function

My C++ is rusty. I'd like MyClass to know nothing about Foo and have a callback to run a function in foo. I don't know how to define callback_pair or how to call SetCallback
class MyClass{
tuple<cb, ptr> callback_pair
int run() {
auto that=callback_pair<1>();
auto cb = callback_pair<0>();
int a=1, b=2, c=3;
auto result = cb(that, a, b, c); //this calls foo.the_function
return result;
}
void SetCallback(tuple<cb, ptr> cb) { callback_pair=cb; )
};
class Foo {
int d;
int the_func(int a, b, c) {
return a+b+c+d
}
}
//myclass.SetCallback(what_do_I_write_here)
Well, MyClass must know something about Foo, namely the signature of whatever method you plan on using as a callback; otherwise, how would it know what to pass in as parameters, or what type to expect to get as output? If the callback signature is known and fixed, for instance int(int,int,int) as you have above, you could use a construction like this:
class MyClass {
std::function<int(int,int,int)> callback;
public:
int run() {
return callback(1,2,3); // or whatever
}
template <typename Class>
void SetCallback (Class& o, int (Class::*m) (int,int,int)) {
callback = [&o,m] (int a, int b, int c) { return (o.*m)(a,b,c); };
}
template <typename Class>
void SetCallback (Class const& o, int (Class::*m) (int,int,int) const) {
callback = [&o,m] (int a, int b, int c) { return (o.*m)(a,b,c); };
}
};
The above implementation of MyClass works as follows: callback is a function object, initially undefined, which takes three ints and returns an int. SetCallback takes two parameters: An object o on which the callback should be performed and a method m on that object which conforms to the signature of callback. It doesn't care what the type of o is; thanks to type-erasure, MyClass never needs to know what it's actually calling.
Take special notice of the two versions of SetCallback -- one each for const and non-const objects. In reality, you should be writing overloads for volatile and const volatile as well, but those are comparatively much rarer than const. In the future, once exception specifications and transactions become part of the type system, we will also have to care about noexcept and synchronization, and the resulting combinatoric explosion of types will be difficult to deal with effectively without some very clever language support. But this example shows you how that sort of code would be written, and it's probably good enough for your purposes.
The implementation looks ugly, but it actually provides a very clean interface; given Foo as you've written above, you would use MyClass's callback functionality like this:
MyClass test;
Foo foo;
foo.d = 4;
test.SetCallback (foo, &Foo::the_func);
int result = test.run(); // result = 10
The above code will work with any type that has a method with the signature int(int,int,int). Note that you must call SetCallback before you call run, or else you'll get a std::bad_function_call exception because the callback hasn't been defined yet.

Vector of std::function with different signatures

I have a number of callback functions with different signatures. Ideally, I would like to put these in a vector and call the appropriate one depending on certain conditions.
e.g.
void func1(const std::string& value);
void func2(const std::string& value, int min, int max);
const std::vector<std::function<void(std::string)>> functions
{
func1,
func2,
};
I realise the above isn't possible, but I wonder if there are any alternatives I should consider. I haven't been able to find any yet, and I've experimented with std::bind but not managed to achieve what I want.
Is such a thing possible?
You haven't said what you expect to be able to do with func2 after putting it in a vector with the wrong type.
You can easily use std::bind to put it in the vector if you know the arguments ahead of time:
const std::vector<std::function<void(std::string)>> functions
{
func1,
std::bind(func2, std::placeholders::_1, 5, 6)
};
Now functions[1]("foo") will call func2("foo", 5, 6), and will pass 5 and 6 to func2 every time.
Here's the same thing using a lambda instead of std::bind
const std::vector<std::function<void(std::string)>> functions
{
func1,
[=](const std::string& s){ func2(s, func2_arg1, func2_arg2); }
};
If you don't know the arguments yet, you can bind references to some variables:
int func2_arg1 = 5;
int func2_arg2 = 6;
const std::vector<std::function<void(std::string)>> functions
{
func1,
std::bind(func2, std::placeholders::_1, std::ref(func2_arg1), std::ref(func2_arg2))
};
Now functions[1]("foo") will call func2("foo", func2_arg1, func2_arg2), and you can assign new values to the integers to pass different arguments to func2.
And using a lambda function instead of std::bind
const std::vector<std::function<void(std::string)>> functions
{
func1,
[&](const std::string& s){ func2(s, func2_arg1, func2_arg2); }
};
This is pretty ugly though, as you need to keep the int variables around for as long as the callable object (the closure or the bind expression) referring to them exists.
What you want is possible through polymorphism. The idea is to create a class with a specific signature, which at runtime will call different methods. For example:
#include <iostream>
#include <functional>
#include <memory>
#include <vector>
void foo(int) {
std::cout << "I'm foo!\n";
}
int bar(char, double) {
std::cout << "I'm bar!\n";
}
class MyFunction {
public:
virtual ~MyFunction(){}
virtual void operator()() = 0;
};
class MyFunctionA : public MyFunction {
public:
virtual void operator()() {
foo(4);
}
};
class MyFunctionB : public MyFunction {
public:
MyFunctionB(std::function<int(char,double)> f, char arg1, double arg2) : fun_(f), arg1_(arg1), arg2_(arg2) {}
virtual void operator()() {
fun_(arg1_, arg2_);
}
private:
std::function<int(char,double)> fun_;
char arg1_;
double arg2_;
};
int main() {
using MyFunPtr = std::unique_ptr<MyFunction>;
std::vector<MyFunPtr> v;
v.emplace_back(new MyFunctionA());
v.emplace_back(new MyFunctionB(bar, 'c', 3.4));
for ( auto&& myfun : v ) {
(*myfun)();
}
return 0;
}
You can make the derived classes as complicated as you need be, but since in the end they all have the same interface you will be able to call all of them.
For C++ 17 std::variant can be used for holding std::functions with different signatures. In this case, the function std::holds_alternative allows you to distinguish between them at runtime:
Sample:
#include <variant>
#include <iostream>
#include <functional>
#include <vector>
using FooInt = std::function<void(int)>;
using FooStr = std::function<void(std::string)>;
using FooVariant = std::variant<FooInt, FooStr>;
void foo(int a){
std::cout << a << std::endl;
}
void bar(std::string a){
std::cout << a << std::endl;
}
int main()
{
std::vector<FooVariant> v;
v.push_back(foo);
v.push_back(bar);
for(auto& f: v){
if (std::holds_alternative<FooInt>(f))
std::get<FooInt>(f)(1);
else if (std::holds_alternative<FooStr>(f))
std::get<FooStr>(f)("hello");
}
}
Direct answer to your question is "NO". Any runtime container would only let you store objects of the same type and std::function<> instantiated with different signatures will be different data types.
Generally the reason you may want to have "a vector of functions with different signatures" is when you have something like the below (three step processing where input interface is unified (buffer& buf and output interface is unified on_event(Event evt)), but the layer in the middle is heterogeneous process_...(...)
receive_message(buffer& buf)
switch(msg_type(buf))
case A:
case B:
...
process_A(A& a, One x, Two y)
...
dispatch(Event evt);
...
process_B(B& b, Three x);
...
dispatch(Event evt);
...
In a solution not involving metaprogramming you'd typically pre-cook a functor doing the end-to-end at initialization time and store those in the vector:
vector <std::function<void(buffer& buf)>> handlers;
If you've got an int and a string, you cannot put them in one vector but you can put them in one struct or std::tuple<>. The same applies for two function types.
std::function erases the exact type of the function object but preserves the function call signature. If you cannot bind the extra arguments in advance as Jonathan Wakely recommends, you can use a boost::variant< std::function<...>, std::function<...> > as your vector member. At the call site you can then check if the vector contains the right kind of function object and call it accordingly.
Not sure how useful this would be for you, it is based on boost::any, redundant parameters are ignored. You can add try...catch for boost::bad_any_cast to prevent crash in case of mismatch between arguments' and parameters' types. Though I think regular std::bind is a better choice.
DEMO
#include <boost/any.hpp>
#include <functional>
#include <vector>
#include <cstddef>
#include <memory>
#include <tuple>
#include <utility>
#include <iostream>
#include <string>
struct IGenericFunction
{
virtual ~IGenericFunction() = default;
virtual void call(boost::any a1 = boost::any{}
, boost::any a2 = boost::any{}
, boost::any a3 = boost::any{}
, boost::any a4 = boost::any{}) = 0;
};
template <typename... Args>
class GenericFunction : public IGenericFunction
{
public:
GenericFunction(std::function<void(Args...)> f) : _f{ f } {}
virtual void call(boost::any a1 = boost::any{}
, boost::any a2 = boost::any{}
, boost::any a3 = boost::any{}
, boost::any a4 = boost::any{}) override
{
call_func(std::make_tuple(a1, a2, a3, a4)
, std::make_index_sequence<sizeof...(Args)>{});
}
private:
template <typename Tuple, std::size_t... Indices>
void call_func(Tuple t, std::index_sequence<Indices...> s)
{
_f(boost::any_cast<
typename std::tuple_element<Indices, Params>::type
>(std::get<Indices>(t))...);
}
std::function<void(Args...)> _f;
using Params = std::tuple<Args...>;
};
template <typename... Args>
std::shared_ptr<IGenericFunction> make_generic_function_ptr(void(*f)(Args...))
{
return std::make_shared<GenericFunction<Args...>>(f);
}
void func1(const std::string& value)
{
std::cout << "func1 " << value << std::endl;
}
void func2(const std::string& value, int min, int max)
{
std::cout << "func2 " << value << " " << min << " " << max << std::endl;
}
int main()
{
std::vector<std::shared_ptr<IGenericFunction>> functions;
functions.push_back(make_generic_function_ptr(&func1));
functions.push_back(make_generic_function_ptr(&func2));
for (auto f : functions)
{
f->call(std::string("abc"), 1, 2);
}
}
As JBL mentioned: how would you call them, if you don't know their signatures?
Think about turning your min, max arguments into a parameter type with some base class Parameter, the callback signature will be void(const std::string&, const Parameter&) or void(const std::string&, const Parameter*) in case you wish nullptr to indicate no additional parameters. Now your callbacks will need to check if they were given the right parameters if any. That may be done by using a visitor, typeid or an enum. There's pros and cons to all of those.
How will you decide on which callback to call? I think you should turn your C-style callbacks into handler objects, they might implement a function bool canHandle(const Parameter&) to test if the handler is applicable to the parameters presented.
Jonathan Wakely and Svalorzen present their approach where the parameters and the function are one and the same object (1-to-1 relationship). In this example they are separate (in case you have multiple-to-multiple relationships):
#include <cassert>
#include <string>
#include <typeinfo>
#include <vector>
class ParameterBase {
public:
ParameterBase(const std::string& value) : m_value(value) { }
virtual ~ParameterBase() { }
const std::string& GetValue() const { return m_value; }
private:
std::string m_value;
};
class HandlerBase {
public:
virtual bool CanHandle(const ParameterBase& params) const = 0;
virtual void Handle(const ParameterBase& params) = 0;
};
class Handler1 : public HandlerBase {
public:
class Parameter : public ParameterBase {
public:
Parameter(const std::string& value) : ParameterBase(value) { }
~Parameter() { }
};
bool CanHandle(const ParameterBase& params) const { return typeid(Parameter) == typeid(params); }
void Handle(const ParameterBase& params) {
assert(CanHandle(params));
const Parameter& p = static_cast<const Parameter&>(params);
// implement callback1
}
};
void foo(const std::vector<HandlerBase*>& handlers) {
Handler1::Parameter params("value");
for(auto handler : handlers)
if(handler->CanHandle(params)) {
handler->Handle(params);
// no break: all handlers may handle params
// with break: only first handler (if any) handles params
}
}
I tried to use the function pointer, and cast std::function<int(int)>* to void*, it can be compiled successful, but sometimes it will cause segmentation fault:
int Fun(int a)
{
std::cout << a << std::endl;
return ++(++a);
}
int main()
{
std::function<int(int)> originPFun = Fun;
void *ppFun;
// ppFun = (void*)&Fun; // This way will cause segmentation fault
ppFun = (void*)&originPFun; // This way can run seuccessful and get right result
std::function<int(int)> *pFun = (std::function<int(int)>*)(ppFun);
std::cout << (*pFun)(5) << std::endl;
system("pause");
return 0;
}

C++ member function pointer with different arguments - or is this bad anyway?

Even though I fear that you will tell me that this topic was covered several time, I dare to ask it, since I was not able to generate a solution. Probably I was just looking for the wrong thing...
Assume that I have a function which receives a "mode" from some external function. Depending on the mode, the function will call different member functions of the same object. This works well for me with member function without any argument, but I did not find out how to extend it to members with arguments. In the real world application, the arguments are not int/float but a more complex classes and the call is nested inside different loops, so I would need to put switch statements several times which I consider ugly.
Question A: Is it possible to easily add support for member functions with arguments based on the existing design? If yes, how does one do that? If possible without external libraries...
Question B: Is this a completely wrong/bad approach? How would I do it better?
Thanks a lot for your help and explanations.
Chris
header excerpt:
typedef void (Object::*memberFunction)();
class Object
{
void memberFnNoArg();
void memberFnWithIntArg(int arg);
void memberFnWithFloatArg(float arg);
}
cpp excerpt:
void function()
{
int mode = getModeFromSomewhere();
int intArg = 33;
float floatArg = 66.6;
switch(mode)
{
case 1:
process(&Object::memberFnNoArg);
break;
case 2:
process(&Object::memberFnWithIntArg, ???); // how can I pass arg?
break;
case 3:
process(&Object::memberFnWithFlaotArg, ???); // how can I pass arg?
break;
default:
// do nothing;
}
}
void process(Object::memberFunction func)
{
Object object;
// loops, called several times, ...
(object.*func)(); // how do I handle different arguments?
}
Wrapping the algorithm in a functor is the right approach, and std::function is a nice functor provided by the Standard library.
But using boost::bind or even std::bind, as suggested by Tomek, is really ugly IMO, and rapidly gets out of control when binding multiple arguments.
If you have a recent compiler you can use a lambda instead, which makes Tomek's example look like:
std::function<void(Object*)> f =
[](Object* const that){ that->memberFnNoArg(); };
int int_value = 22;
std::function<void(Object*)> f2 =
[int_value](Object* const that){ that->memberFnIntArg(int_value); };
Object o;
f(&o);
f2(&o);
There are a few characters to set up the lambda, but the member access syntax is extremely natural and it's obvious how you make changes.
Of course, you can make the parameter a reference to the object if you really want, but I prefer pointers here.
Have a look at std::function and std::bind, they seem to fit perfectly what you need.
EDIT:
std::function<void(Object &)> f = &Object::memberFnNoArg;
std::function<void(Object &)> f2 = std::bind(&Object::memberFnWithIntArg, _1, 22);
Object o;
f(o);
f2(o);
should work out of a box as far as I remember.
Is this what you need?
You could use a varadic template function:
template <typename... Args>
void process(void (Object::*func)(Args...),Args... args)
{
Object object;
// loops, called several times, ...
(object.*func)(args...);
}
Here is a full example:
#include <iostream>
struct Object
{
void memberFnNoArg()
{
std::cout << "Object::memberFnNoArg()\n";
}
void memberFnWithIntArg(int arg)
{
std::cout << "Object::memberFnWithIntArg(" << arg << ")\n";
}
void memberFnWithFloatArg(float arg)
{
std::cout << "Object::memberFnWithFloatArg(" << arg << ")\n";
}
};
template <typename... Args>
void process(void (Object::*func)(Args...),Args... args)
{
Object object;
// loops, called several times, ...
(object.*func)(args...);
}
int main()
{
process(&Object::memberFnNoArg);
process(&Object::memberFnWithIntArg,5);
process(&Object::memberFnWithFloatArg,2.7F);
return 0;
}
One way I see around this would be to use a variable arguments (pretty much like printf, sprintf does it). (Or maybe with stdc libraries, passing a list of different types.)
The reason is, that the argument list is part of the function pointer type, so you'd essentially need a process function with variable arguments and then the memberFunction probably needs to be one of that type too.
Below is a plain (non member) sample of how to pick up variable arguments (member functions would essentially work the same). See stdarg.h.
typedef void (*var_function)(int typearg, ...);
void print_arg(int typearg, ...)
{
va_list ap;
int i;
va_start(ap, typearg);
if (typearg==1) { // int
int i= va_arg(ap, int);
printf("%d ", i);
}
else
if (typearg==2) { // float
float f= va_arg(ap, float);
printf("%f ", f);
}
else
if (typearg==3) { // char *
char *s= va_arg(ap, char *);
printf("%s ", s);
}
....
va_end(ap);
}
// calling function with different types
int main()
{
print_arg(1, 999);
print_arg(2, 3.1415926);
print_arg(3, "Hello");
....
process(print_arg, 3, "via pointer);
Sounds like packaged_task. Also check out Tomek's suggestion.
Though IRL I'd go ahead asking lots of questions on why you need it in the first place. Possibly your work could be better covered using std::future or other higher level facility,
Can't each function (memberFn**) be a member of argument classes ?
class BaseArg
{
virtual void Fn() = 0;
};
class IntArg : public BaseArg
{
void Fn();
};
class FloatArg : public BaseArg
{
void Fn();
};
void function()
{
int mode = getModeFromSomewhere();
BaseArg* pArg;
if ( mode ... ){
pArg = new IntArg( 33 );
}
else {
pArg = new FloatArg( 66.6 );
}
pArg->Fn(); // Call the right function without a switch
// and without knowing the arguments
}
Same as other answers, but to show for member methods:
#include <iostream>
class Object
{
public:
void memberFnNoArg()
{
std::cout << "Object::memberFnNoArg()\n";
}
void memberFnWithIntArg(int arg)
{
std::cout << "Object::memberFnWithIntArg(" << arg << ")\n";
}
void memberFnWithFloatArg(float arg)
{
std::cout << "Object::memberFnWithFloatArg(" << arg << ")\n";
}
bool memberFnWithBoolReturn(int)
{
return true;
}
template <typename... Args>
void process(void (Object::*func)(Args...),Args... args);
// overload process
template <typename... Args>
bool process(bool (Object::*func)(Args...),Args... args);
};
template <typename... Args>
void process( void (Object::*func)(Args...),class Object* obj,Args... args)
{
(obj->*func)(args...);
}
template <typename... Args>
bool process( bool (Object::*func)(Args...),class Object* obj,Args... args)
{
return ((obj->*func)(args...)) ;
}
int main()
{
Object object;
process(&Object::memberFnNoArg,&object);
process(&Object::memberFnWithIntArg,&object,5);
process(&Object::memberFnWithFloatArg,&object,2.7F);
// overloaded process
printf("%d\n",process(&Object::memberFnWithBoolReturn,&object,1));
return 0;
}

C++ variable number of arguments

I need to define a virtual function that can take variable number of arguments, problem is c style ellipses does not work for non pod types, I have limited amount of memory (2KB) so i am trying to avoid allocating temp object just to pass to the function, all arguments will be of the same type (a custom shared pointer), I also don't have access to stl or boost. Is there a c++ trick that would allow me to call a func with variable arguments?
Assuming your argument types are of class Arg, you can try this:
class ArgUser {
public:
// syntactic sugar:
void method() { // nullary
doMethod();
}
void method( const Arg & a1 ) { // unary
doMethod( &a1 );
}
void method( const Arg & a1, const Arg & a2 ) { // binary
doMethod( &a1, &a2 );
}
// and so on, until max arity
private:
// actual virtual function:
virtual void doMethod( const Arg * a1=0, const Arg * a2=0 /*etc, until max arity */ ) = 0;
};
This solution has the following properties:
It uses the NVI idiom
It uses pointers because they will not cause temporaries to be created, even for unused default arguments.
It encapsulates the ugly pointer juggling in (inline) wrapper methods.
An alternative solution (that may or may not be more efficient) is this:
class AltArgUser {
public:
// syntactic sugar:
void method() { // nullary
doMethod( 0, 0 );
}
void method( const Arg & a1 ) { // unary
doMethod( &&a1, 1 );
}
void method( const Arg & a1, const Arg & a2 ) { // binary
const Arg * args[] = { &a1, &a2 };
doMethod( args, 2 );
}
// and so on, until max arity
private:
// actual virtual function:
virtual void doMethod( const Arg * args[], size_t numArgs ) = 0;
};
To decide which one to use, you need to study the assembler generated for each method on your particular platform. Whatever you choose, you should definitely keep the wrapper functions.
Define the function to take a pointer to an array of parameters and a parameter for the size of the array.
Also, if you do not want to hard code a fixed sized array you could use alloca to allocate the storage on the stack and not worry about a trip to the heap or calling free.
Pointers to shared pointers are PODs, could you change the prototype to use the memory location of each argument? Like this (not tested):
shared_ptr arg1;
shared_ptr arg2;
ClassWithVirtualFunction c;
c.yourVirtualFunction(&arg1, &arg2, NULL);
ClassWithVirtualFunction
{
virtual void yourVirtualFunction(shared_ptr* first, ...)
{
va_list marker;
va_start( marker, first );
shared_ptr* current=first;
while (current != NULL)
{
/* do stuff with *current */
current = va_arg( marker, shared_ptr* );
}
va_end(marker);
}
}
You can use a fixed array that is actually faster and takes less space than variable number of arguments. Because variable number of arguments does a lot of checks and safety.
mytype arr[3];
arr[0] = a;
// etc
myfunction(arr, 3);
Perhaps if you already have your own custom pointer type, you could define your own basic linked list class (this is C++ after all), with the last "pointer to next" being NULL to indicate the end of the variable number of args.
Something like this:
class MyPointer
{
// Whatever you have/want
};
class MyArgs
{
static int nargs; // Static class variable for total number of args
MyPointer* data;
MyArgs* next;
public:
MyArgs(int nargs)
{
// Some funky constructor to create required number of args...
}
MyPointer* operator[](int at)
{
// Nice overloaded operator for you to get at data
}
};
class PlanToDoStuff
{
public:
virtual void foobar(MyArgs)=0;
};
class ActuallyDoStuff: public PlanToDoStuff
{
public:
void foobar(MyArgs)
{
// Do stuff with args...
}
};
int main()
{
MyArgs args(3);
ActuallyDoStuff dosomething;
dosomething.foobar(args);
}