I want to use boost::any to store heterogeneous function pointers. I get an exception when I try to use boost::any_cast to recast to the function pointer.
Is what I want to do even allowed?
.h:
typedef void(*voidFunction)(void);
struct functionInfo{
CString functionName;
boost::any functionPointer;
};
void foo();
int foo2(int a);
.cpp
void foo()
{
;//do something
}
int foo2(int a)
{
;//do something
}
void main()
{
vector<functionInfo> functionList;
functionInfo myInfo;
myInfo.functionName = _T("foo");
myInfo.functionPointer = &foo;
functionList.push_back(myInfo);
myInfo.functionName = _T("foo2");
myInfo.functionPointer = &foo2;
functionList.push_back(myInfo);
voidFunction myVoidFunction = boost::any_cast<voidFunction>(functionList[0].functionPointer);
}
----EDIT----
Ok, you are right, the reason why it acted like this is because foo is a class member function.
Meaning:
void MyClass::foo();
myInfo.functionPointer = &MyClass::foo;
so I needed to typedef:
typedef void(MyClass::*voidClassFunction)(void);
voidClassFunction myVoidFunction = boost::any_cast<voidClassFunction>(functionList[0].functionPointer);
Is what I want to do even allowed?
Absolutely. As long as you cast it back to exactly the type you gave it.
And that's your problem. You don't. foo2
is not a voidFunction
. Therefore, you cannot cast it to one.
The purpose of boost::any
is to have a void*
that is guaranteed to either work correctly according to the C++ standard or throw an exception. The C++ standard allows the conversion of any (non-member) pointer type to a void*
. It also allows conversion of a void*
back to a type, provided that the type being provided is exactly the same type as the original. If it's not, welcome to undefined behavior.
boost::any
exist to prevent undefined behavior by storing type information with the void*
. It will rightly throw an exception when you attempt to cast something to the wrong type. As you do here. boost::any
is not a way to pretend that types don't exist and to pretend that you can turn anything into something else. It's just a type-safe typeless container. You still need to know what you actually put there.
There is no way to store a list of functions with arbitrary argument lists and call them with the same argument list. The user must provide a function or functor with the right argument list that you expect. boost::bind
is a way to adapt a function/functor for a particular argument list, but the user must explicitly use it.
The best you can do is have a list of specific function parameter sets that you accept, stored in a boost::variant
object. You can use a visitor to figure out which particular function to call.