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.
Related
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.
I am trying to implement a generic event handling system with templates, but I get an error at compile time when I try to add the function to a list.
error C2298: missing call to bound pointer to member function
class EventManager
{
public:
template <class OBJECT>
void subscribe(std::string eventName, OBJECT *obj, void(OBJECT::*newEvent)(Event))
{
(obj->*newEvent)(Event()); // I can call the event just fine if I execute it alone
abc.push_back(obj->*newEvent); // Error c2298 here
}
static EventManager* Get();
private:
std::vector<void(*)(Event)> eventsList;
};
And this is where I call it:
EventManager::Get()->subscribe("EventName", this, &TestClass::eventTest);
void ATideManager::eventTest(Event event)
{
//Test
}
I am quite new to C++ and templates, so I'm sure the solution is easy, but I don't understand why I can call the event but not add it to the vector. Do you know how I could possibly do that?
As the documentation for that error message says:
A pointer to member-function expression must call the member function.
In other words, you cannot store a pointer to member-function including the object on which to call it, for later use.
Here is a simpler example using names similar to yours:
struct Object
{
void f() {}
};
int main()
{
Object obj;
using member_function_pointer = void (Object::*)();
member_function_pointer ptr = &Object::f;
(obj.*ptr)();
(obj.*ptr); // error
}
And this makes a lot of sense. Your abc is probably a vector of pointers to member-function (or just a vector of function pointers); it cannot magically store an object along with each pointer in it.
Generally, pointers to member functions are not exactly the nicest, cleanest or best feature of C++, and the awful syntax renders every piece of code using it completely unreadable. Fortunately, C++11 introduced std::function and lambdas, which gives you a much better alternative:
#include <functional>
#include <iostream>
#include <string>
#include <vector>
struct Event
{
int i;
};
class EventManager
{
public:
void subscribe(std::string const& eventName,
std::function<void(Event const&)> event)
{
abc.push_back(event);
}
static EventManager& get()
{
static EventManager instance;
return instance;
}
void onEvent(Event const& event)
{
for (auto&& f : abc)
{
f(event);
}
}
private:
EventManager() {}
EventManager(EventManager const&) = delete;
EventManager& operator=(EventManager const&) = delete;
std::vector<std::function<void(Event const&)>> abc;
};
struct ATideManager
{
void f()
{
EventManager::get().subscribe("EventName",
[=](Event const& event) { eventTest(event); });
}
void eventTest(Event const& event)
{
std::cout << "eventTest: " << event.i << "\n";
}
};
int main()
{
ATideManager manager;
manager.f();
Event some_event{ 123 };
EventManager::get().onEvent(some_event);
}
I've also fixed your needless use of pointers where references can be used, and some const-correctness issues.
obj->*newEvent is invalid. A member function pointer can be used in this way only to call the pointed-to member function.
You can however use std::vector<std::function<void(Event)>> and
abc.push_back(std::bind(newEvent, obj, std::placeholders::_1);
std::bind reference
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;
}
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;
}
i was wondering if there was a way to do this in C++?
void func1(const std::string& s)
{
std::cout << s << std::endl;
}
void func2(int me)
{
std::cout << me << std::endl;
}
int main()
{
std::map<std::string, boost::function< ??? > > a_map;
a_map["func1"] = &func1;
a_map["func1"]("HELLO");
}
Is there any way to do what i have above using boost function and a map?
There are ways to store the functions, the problem is, in order to be able to call the function with the desired argument you'd have to know the calling signature of the function anyways, and if you have that information, you might as well use separate maps, or use a more complicated object than boost::function.
If you're willing to do a bit of work and have a finite number of signatures, you could just do something like this:
class MultiFunc
{
protected:
MultiFunc() {}
public:
typedef void (*stringFunc)(const std::string&);
typedef void (*intFunc)(int);
static MultiFunc *Create(stringFunc function);
static MultiFunc *Create(intFunc function);
virtual void operator()(const string &) { throw exception(); }
virtual void operator()(int) { throw exception(); }
virtual ~MultiFunc();
};
class MultiFuncString : public MultiFunc
{
private:
stringFunc Function;
public:
MultiFuncString(stringFunc function) : Function(function) {}
virtual void operator()(const string &arg) { Function(arg); }
};
class MultiFuncInt : public MultiFunc
{
private:
intFunc Function;
public:
MultiFuncInt(intFunc function) : Function(function) {}
virtual void operator()(int arg) { Function(arg); }
};
MultiFunc *MultiFunc::Create(MultiFunc::stringFunc function)
{
return new MultiFuncString(function);
}
MultiFunc *MultiFunc::Create(MultiFunc::intFunc function)
{
return new MultiFuncInt(function);
}
void func1(const std::string& s)
{
std::cout << s << std::endl;
}
void func2(int me)
{
std::cout << me << std::endl;
}
int main()
{
map<string, MultiFunc *> a_map;
a_map["func1"] = MultiFunc::Create(&func1);
(*a_map["func1"])("Hello");
a_map["func2"] = MultiFunc::Create(&func2);
(*a_map["func2"])(3);
// Remember to delete the MultiFunc object, or use smart pointers.
}
This outputs:
Hello
3
Unfortunately, you can't make templated virtual functions or you easily generalize this all.
You probably can't use the std::map since it is a homogenous container. Try, something like boost::variant (they support the visitor pattern) or boost::tuple
What you are trying to do sounds a little weird. Normally, you would have a container be a collection of abstract types or objects or functions with the same signature. Otherwise, how would you know how to call the function when you are iterating the container? I like to make the container a collection of function objects with a known signature, then use Boost.Bind to store closures that call the function with additional arguments.
For example:
typedef boost::function<void, void> Function;
typedef std::map<std::string, Function> Functions;
Functions functions:
void foo()
{
...
}
functions["foo"] = foo;
void bar(std::string &s)
{
...
}
// binds the value "hello" to the s parameter
functions["bar"] = boost::bind(bar, "hello");
read this link below. It talks about using boost::bind to store the function pointers in std::map
http://www.gamedev.net/community/forums/topic.asp?topic_id=526381&whichpage=1�
store interfaces:
struct IStringData
{
virtual std::string get() const = 0;
virtual ~IStringData() {}
};
and make implementaions, one will just hold string value, other implementation will store functor, maybe you will have other implementations in future.
No. You can't. Since boost::function isn't polymorphic, it breaks down there. (It takes a fixed set of argument types.)
There was talk about work in that direction on the boost mail-list, though, so search the archives and see if there is some code you could youse.
A workaround would be to use boost::function but then you need to add to the map not your real functions (i.e. func1/func2) but dispatch functions that extracts the type from the any-container and calls the real function. (And bails if it's wrong, just as in any dynamic langugage.)