Vector of std::function with different signatures - c++

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;
}

Related

How to Store Variadic Template Arguments Passed into Constructor and then Save them for Later Use?

I am curious how one would go about storing a parameter pack passed into a function and storing the values for later use.
For instance:
class Storage {
public:
template<typename... Args>
Storage(Args... args) {
//store args somehow
}
}
Basically I am trying to make a class like tuple, but where you don't have to specify what types the tuple will hold, you just pass in the values through the constructor.
So for instance instead of doing something like this:
std::tuple<int, std::string> t = std::make_tuple(5, "s");
You could do this:
Storage storage(5, "s");
And this way you could any Storage objects in the same vector or list. And then in the storage class there would be some method like std::get that would return a given index of an element we passed in.
Since run will return void, I assume all the functions you need to wrap can be functions that return void too.
In that case you can do it like this (and let lambda capture do the storing for you):
#include <iostream>
#include <functional>
#include <string>
#include <utility>
class FnWrapper
{
public:
template<typename fn_t, typename... args_t>
FnWrapper(fn_t fn, args_t&&... args) :
m_fn{ [=] { fn(args...); } }
{
}
void run()
{
m_fn();
}
private:
std::function<void()> m_fn;
};
void foo(const std::string& b)
{
std::cout << b;
}
int main()
{
std::string hello{ "Hello World!" };
FnWrapper wrapper{ foo, hello };
wrapper.run();
return 0;
}
OK, what you're asking is type erasure. Typical way of implementing it is via a virtual function inherited by a class template.
Live demo here: https://godbolt.org/z/fddfTEe5M
I stripped all the forwards, references and other boilerplate for brevity. It is not meant to be production code by any means.
#include<memory>
#include <iostream>
#include <stdexcept>
struct Fn
{
Fn() = default;
template<typename F, typename...Arguments>
Fn(F f, Arguments...arguments)
{
callable =
std::make_unique<CallableImpl<F, Arguments...>>(f, arguments...);
}
void operator()()
{
callable
? callable->call()
: throw std::runtime_error("empty function");
}
struct Callable
{
virtual void call() =0;
virtual ~Callable() = default;
};
template<typename T, typename...Args_>
struct CallableImpl : Callable
{
CallableImpl(T f, Args_...args)
: theCallable(f)
, theArgs(std::make_tuple(args...))
{}
T theCallable;
std::tuple<Args_...> theArgs;
void call() override
{
std::apply(theCallable, theArgs);
}
};
std::unique_ptr<Callable> callable{};
};
void f(int a)
{
std::cout << a << '\n';
}
int main(int, char*[])
{
Fn fx{f, 3};
fx();
char x = 'q';
Fn flambda( [x](){std::cerr << x << '\n';} );
flambda();
}
The "meat" of it lies here:
struct Callable
{
virtual void call() =0;
virtual ~Callable() = default;
};
template<typename T, typename...Args_>
struct CallableImpl : Callable
{
CallableImpl(T f, Args_...args)
: theCallable(f)
, theArgs(std::make_tuple(args...))
{}
T theCallable;
std::tuple<Args_...> theArgs;
void call() override
{
std::apply(theCallable, theArgs);
}
};
Callable is just the interface to access the object. Enough to store a pointer to it and access desired methods.
The actual storage happens in its derived classes:template<typename T, typename...Args_> struct CallableImpl : Callable. Note the tuple there.
T is for storing the actual object, whatever it is. Note that it has to implement some for of compile-time interface, in C++ terms referred to as a concept. In that case, it has to be callable with a given set of arguments.
Thus it has to be known upfront.
The outer structure holds the unique_ptr to Callable but is able to instantiate the interface thanks to the templated constructor:
template<typename F, typename...Arguments>
Fn(F f, Arguments...arguments)
{
callable =
std::make_unique<CallableImpl<F, Arguments...>>(f, arguments...);
}
What is the main advantage of it?
When done properly, it has value semantics. Effectively, it can be used to represent a sort of polymorphism without derivation, note T doesn't have to have a common base class, it just has to be callable in one way or another; this can be used for addition, subtraction, printing, whatever.
As for the main drawbacks: a virtual function call (CallableImpl stored as Callable) which may hinder performance. Also, getting back the original type is difficult, if not nearly impossible.

Curry a function that takes abstract arguments in CPP

I would like to curry a function that takes an abstract argument. This makes my compiler angry:
#include <functional>
class MyAbstractParentClass {
public:
virtual void someVirtualMethod() = 0;
};
class MyConcreteChildClass: public MyAbstractParentClass {
public:
virtual void someVirtualMethod() override {}
};
void myFunction(const MyAbstractParentClass& myAbstractObject) {}
int main(int argc, const char * argv[]) {
const MyAbstractParentClass& myChildObject = MyConcreteChildClass();
myFunction(myChildObject); // all good here
const auto myCurriedFunction = std::bind(myFunction, myChildObject); // error here
myCurriedFunction(); // we never get here
}
Is there a way I can make this work without resorting to pointers?
std::bind copies its argument, you might use reference with std::reference_wrapper
const auto myCurriedFunction = std::bind(myFunction, std::ref(myChildObject));
or use lambda:
const auto myCurriedFunction = [&](){ return myFunction(myChildObject); };
If you want to curry a function, you can use boost::hana::curry, as shown below:
#include <boost/hana/functional/curry.hpp>
#include <iostream>
int f(int x,int y,int z) {
return x + y + z;
};
int main {
auto constexpr f_curried = boost::hana::curry<3>(f);
auto constexpr f12 = f_curried(1)(2);
std::cout << f12(3) << '\n';
}
However, in your case you seem to be "partially" applying the function, rather than currying it. I use quotes because you're actually passing to it all the arguments it needs, and you're just delaying the call. To accomplish this, you can use boost::hana::partial from the <boost/hana/functional/partial.hpp> header (but you still have to wrap the object in a reference, as shown in the other answer which actually tells you what's wrong in your original code):
using boost::hana::partial;
const auto myCurriedFunction = partial(myFunction, std::ref(myChildObject));

Vector of pointers to member functions with multiple objects c++

Considering this following code :
class A
{
public:
void aFoo() {}
};
class B
{
public:
void bFoo() {}
};
class C
{
public:
void c1Foo() {}
void c2Foo() {}
};
Regardless the code architecture, is it possible to create a vector of pointers to member functions even if those functions are in multiple classes ?
In this case, inheritance is not a solution because we don't know how many functions we want to use in a class (class C has two functions). But we know they all have the same prototype.
Member functions of different classes have different types. So in order to have any homogeneous container (like std::vector or std::array) of those you'll need to wrap them in some value type that may represent them all (like boost::variant or boost::any).
On the other hand if all you need are member functions of a specific type (for example void()) and you don't mind passing the object on which they should be called before hand, then you can just store them as std::function<void()> (for this specific example) and just call std::bind on them before storing them in the container.
As an example, given:
A a; B b; C c;
std::vector<std::function<void()>> vector {
std::bind(&A::aFoo, a),
std::bind(&B::bFoo, b),
std::bind(&C::c1Foo, c),
std::bind(&C::c2Foo, c)
};
you would be able to call:
for (auto fn : vector)
fn();
Live demo
I am not sure what you want to achieve so this may not be very helpful but here it is anyway.
As others have said you cannot create a std::vector for this as the prototypes are different. You can however create a std::tuple like this:
std::tuple<void (A::*)(), void (B::*)(), void (C::*)()> x(&A::aFoo, &B::bFoo, &C::c1Foo);
Assuming you have a an instance of a class, say A a then you can call the function as in (a.*std::get<0>(x))().
If you have stored your objects in a tuple as well, then you can iterate over them. The following code will do just that (assumes you have C++14 and Boost in your system)
#include <iostream>
#include <tuple>
#include <type_traits>
#include <boost/mpl/find_if.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/fusion/include/mpl.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <functional>
class A
{
public:
void aFoo()
{
std::cout << "A" << std::endl;
}
};
class B
{
public:
void bFoo()
{
std::cout << "B" << std::endl;
}
};
class C
{
public:
void c1Foo()
{
std::cout << "C1" << std::endl;
}
void c2Foo() {}
};
// functor used by boost to iterate over the tuple
template <class Tuple>
struct functor
{
functor(Tuple t)
: m_tuple(t)
{
}
template <class X>
void operator()(X& x) const
{
using namespace boost::mpl;
using iter = typename find_if<Tuple, std::is_same < placeholders::_1, void (X::*)()> >::type;
using type = typename deref<iter>::type;
return (x.*std::get<type>(m_tuple))();
}
private:
Tuple m_tuple;
};
template <class Tuple>
functor<Tuple> make_functor(Tuple t)
{
return functor<Tuple>(t);
}
int main()
{
std::tuple<void (A::*)(), void (B::*)(), void (C::*)() > x(&A::aFoo, &B::bFoo, &C::c1Foo);
std::tuple<A, B, C> y;
boost::fusion::for_each(y, make_functor(x));
}
Live demo here:
http://coliru.stacked-crooked.com/a/e840a75f5b42766b

Store templated objects as member objects

suppose you have some code like this:
struct Manager
{
template <class T>
void doSomething(T const& t)
{
Worker<T> worker;
worker.work(t);
}
};
A "Manager" object is created once and called with a few diffent types "T", but each type T is called many times. This might be, in a simplified form, like
Manager manager;
const int N = 1000;
for (int i=0;i<N;i++)
{
manager.doSomething<int>(3);
manager.doSomething<char>('x');
manager.doSomething<float>(3.14);
}
Now profiling revealed that constructing a Worker<T> is a time-costly operation and it should be avoided to construct it N times (within doSomething<T>). For thread-safety reasons it is ok to have one Worker<int>, one Worker<char> and Worker<float> per "Manager", but not one Worker<int> for all Managers. So usually I would make "worker" a member variable. But how could I do this in the code above? (I do not know in advance which "T"s will be used).
I have found a solution using a std::map, but it is not fully typesafe and certainly not very elegant. Can you suggest a typesafe way without constructing Worker<T> more often than once per "T" without virtual methods?
(please note that Worker is not derived from any template-argument free base class).
Thanks for any solution!
You can use something like a std::map<std::type_info,shared_ptr<void> > like this:
#include <map>
#include <typeinfo>
#include <utility>
#include <functional>
#include <boost/shared_ptr.hpp>
using namespace std;
using namespace boost;
// exposition only:
template <typename T>
struct Worker {
void work( const T & ) {}
};
// wrapper around type_info (could use reference_wrapper,
// but the code would be similar) to make it usable as a map<> key:
struct TypeInfo {
const type_info & ti;
/*implicit*/ TypeInfo( const type_info & ti ) : ti( ti ) {}
};
// make it LessComparable (could spcialise std::less, too):
bool operator<( const TypeInfo & lhs, const TypeInfo & rhs ) {
return lhs.ti.before( rhs.ti );
}
struct Manager
{
map<TypeInfo,shared_ptr<void> > m_workers;
template <class T>
Worker<T> * findWorker()
{
const map<TypeInfo,shared_ptr<void> >::const_iterator
it = m_workers.find( typeid(T) );
if ( it == m_workers.end() ) {
const shared_ptr< Worker<T> > nworker( new Worker<T> );
m_workers[typeid(T)] = nworker;
return nworker.get();
} else {
return static_cast<Worker<T>*>( it->second.get() );
}
}
template <typename T>
void doSomething( const T & t ) {
findWorker<T>()->work( t );
}
};
int main() {
Manager m;
m.doSomething( 1 );
m.doSomething( 1. );
return 0;
}
This is typesafe because we use type_info as an index into the map. Also, the workers are properly deleted even though they're in shared_ptr<void>s because the deleter is copied from the original shared_ptr<Worker<T> >s, and that one calls the proper constructor. It also doesn't use virtual functions, although all type erasure (and this is one) uses something like virtual functions somewhere. Here, it's in shared_ptr.
Factoring the template-independent code from findWorker into a non-template function to reduce code bloat is left as an exercise for the reader :)
Thanks to all commenters who pointed out the mistake of using type_info as the key directly.
You can add std::vector of boost::variants or boost::anys as member of your class. And append to it any worker you want.
EDIT: The code bellow will explain how
struct Manager
{
std::vector<std::pair<std::type_info, boost::any> > workers;
template <class T>
void doSomething(T const& t)
{
int i = 0;
for(; i < workers.size(); ++i)
if(workers[i].first == typeid(T))
break;
if(i == workers.size())
workers.push_back(std::pair<std::type_info, boost::any>(typeid(T).name(), Worker<T>());
any_cast<T>(workers[i]).work(t);
}
};
I was already working on an answer similar to mmutz's by time he posted his. Here's a complete solution that compiles and runs under GCC 4.4.3. It uses RTTI and polymorphism to lazily construct Worker<T>s and store them in a map.
#include <iostream>
#include <typeinfo>
#include <map>
struct BaseWorker
{
virtual ~BaseWorker() {}
virtual void work(const void* x) = 0;
};
template <class T>
struct Worker : public BaseWorker
{
Worker()
{
/* Heavyweight constructor*/
std::cout << typeid(T).name() << " constructor\n";
}
void work(const void* x) {doWork(*static_cast<const T*>(x));}
void doWork(const T& x)
{std::cout << typeid(T).name() << "::doWork(" << x << ")\n";}
};
struct TypeofLessThan
{
bool operator()(const std::type_info* lhs, const std::type_info* rhs) const
{return lhs->before(*rhs);}
};
struct Manager
{
typedef std::map<const std::type_info*, BaseWorker*, TypeofLessThan> WorkerMap;
~Manager()
{
// Delete all BaseWorkers in workerMap_
WorkerMap::iterator it;
for (it = workerMap_.begin(); it != workerMap_.end(); ++it)
delete it->second;
}
template <class T>
void doSomething(T const& x)
{
WorkerMap::iterator it = workerMap_.find(&typeid(T));
if (it == workerMap_.end())
{
it = workerMap_.insert(
std::make_pair(&typeid(T), new Worker<T>) ).first;
}
Worker<T>* worker = static_cast<Worker<T>*>(it->second);
worker->work(&x);
}
WorkerMap workerMap_;
};
int main()
{
Manager manager;
const int N = 10;
for (int i=0;i<N;i++)
{
manager.doSomething<int>(3);
manager.doSomething<char>('x');
manager.doSomething<float>(3.14);
}
}
map<std::type_info, BaseWorker*> doesn't work because type_info is not copy-constructible. I had do use map<const std::type_info*, BaseWorker*>. I just need to check that typeid(T) is guaranteed to always return the same reference (I think it is).
It doesn't matter whether or not typeid(T) returns the same reference, because I always use type_info::before do to all comparisons.
something like this will work:
struct Base { };
template<class T> struct D : public Base { Manager<T> *ptr; };
...
struct Manager {
...
Base *ptr;
};

What is the best way to expose a callback API - C++

I have a C++ library that should expose some system\ resource calls as callbacks from the linked application. For example: the interfacing application (which uses this library) can send socket management callback functions - send, receive, open, close etc., and the library will use this implementation in stead of the library's implementation.
(This way enables the application to manage the sockets by itself, can be useful).
This library has to expose also more callbacks, like, for example, a password validation, so I wonder if there is a preferred method to expose the callback sending option in one API.
Something like:
int AddCallbackFunc (int functionCallbackType, <generic function prototype>, <generic way to pass some additional arguments>)
Then within my library I will assign the callback to the appropriate function pointer according to the functionCallbackType parameter.
Is there any way to implement it in a generic way which will fit ANY function prototype and ANY additional arguments?
Your help will be more than appreciated...
Thanks!
Why not have it accept a 0 argument functor and just have the user use boost::bind to build the arguments into it before registering it? Basically example (calls instead of stores, but you get the point):
#include <tr1/functional>
#include <iostream>
void callback(const std::tr1::function<int()> &f) {
f();
}
int x() {
std::cout << "x" << std::endl;
return 0;
}
int y(int n) {
std::cout << "y = " << n << std::endl;
return 0;
}
int main(int argc, char *argv[]) {
callback(x);
callback(std::tr1::bind(y, 5));
}
EDIT: There is an option B, which is to basically implement what bind does under the hood with structures to store all the needed info and inheritance for polymorphism... it becomes a mess real quick. I would not recommend it, but it will work. You can also save from grief by forcing a return type of int, but that only saves you a little.
#include <iostream>
struct func_base {
virtual int operator()() = 0;
};
// make one of these for each arity function you want to support (boost does this up to 50 for you :-P
struct func0 : public func_base {
typedef int (*fptr_t)();
func0(fptr_t f) : fptr(f) {
}
virtual int operator()() { return fptr(); }
fptr_t fptr;
};
// demonstrates an arity of 1, templated so it can take any type of parameter
template <class T1>
struct func1 : public func_base {
typedef int (*fptr_t)(T1);
func1(fptr_t f, T1 a) : fptr(f), a1(a) {
}
virtual int operator()() { return fptr(a1); }
fptr_t fptr;
T1 a1;
};
void callback(func_base *f) {
(*f)();
}
int x() {
std::cout << "x" << std::endl;
return 0;
}
int y(int n) {
std::cout << "y = " << n << std::endl;
return 0;
}
int main(int argc, char *argv[]) {
// NOTE: memory leak here...
callback(new func0(x));
callback(new func1<int>(y, 5));
}
If you don't want to go for any of the C++ options available; std::tr1::function, functors, polymorphism with common base class etc. you can use the C method instead.
The client passes a callback and a pointer to its arguments as a void*, then the callback casts the void* to the correct type when it's called. You'll need to store the void* alongside the callback and you'll need to be very careful with object lifetimes.
int AddCallbackFunc (int type, int(*callback)(void*), void* callbackData)
It can be done, using a combination of template and type-erasure.
The idea is to take any type and wrap it into an object with a known interface.
class CallbackBase
{
public:
virtual ~CallbackBase();
virtual void execute();
};
template <class T>
class Callback: public CallbackBase
{
public:
explicit Callback(T functor): mFunctor(functor) {}
void execute() { mFunctor(); }
private:
T mFunctor;
};
And now, we can wrap it:
template <class Function>
int AddCallbackFunc (int functionCallbackType, Function f)
{
std::auto_ptr<CallbackBase> c(new Callback<Function>(f));
// do something with `c`.
}
I leave it up to you to bind the arguments, the no library way is to create a functor.
Sounds like you're looking for a Functor. Basically a class for each type of callback, with the arguments as data members and operator() to invoke the functionality.