C++ generic object factory by string name - c++

I need a way to instantiate objects based on its class name passed by as a std::string. This is working right now, but need to be generalized:
void* create(std::string name) {
if(name == "classOne") return new ClassOne();
else if(name == "classTwo") return new ClassTwo();
/* ... */
}
What i do not have:
Control over the classes to be instantiated: could be thirty party classes. No changes may be done to this classes (i.e. base ancestor, polymorphic creator method, etc...)
Full class name listing: more classes could be added later and should not incur in changes to this factory.
Wrappers around the classes to be instantiated: As a result of the previous two points.
Anything else is a go.
The best use case scenario will be:
int main() {
void *obj = create("classTree"); // create object based on the string name
/* ... */
// once we know by context which specific class we are dealing with
ClassTree *ct = (ClassTree*)obj; // cast to appropiate class
std::cout << ct->getSomeText() << std::endl; // use object
}
As a side, and maybe irrelevant note, take in account the object to be instantiated may come from a class or a struct.
ADDED INFORMATION
I see more context is needed. Here is my particular use case, simplified:
// registration mechanism
int main() {
std::map< std::string, void(*func)(std::string, void*) > processors; // map of processors by class name
processors["ClassFour"] = (void(*)(std::string, void*)) &classFourMessageProcessor; // register processor (cast needed from specific to generic)
}
// function receiving string messages
void externalMessageHandler(std::string msg) {
std::string objType = extractTypeFromMessageHeader(msg); // extract type from message
// now that we know what we are dealing with, create the specific object
void *obj = create(objType); // << creator needed
processors[objType](msg, obj); // dispatch message to process
}
// previously registered message processor
void classFourMessageProcessor(std::String msg, ClassFour *obj) {
std::string streetAddress = msg.substr(10, 15); // knowing the kind of message we can extract information
obj->moveTheEtherTo(streetAddress); // use the created object
}
ADDED INFORMATION
I am using C++11 with the latest GNU compiler.

You can just store a factory function for every class type. An easy way is to use a template
template <typename T>
void* creator() {
return new T();
}
and store those in the map as well (i.e. "ClassFour" links to creator<ClassFour> and to ClassFourMessageProcessor).
Edit: for clarification, processors becomes a
typedef void* (*CreatorFunc)();
typedef void (*ProcessorFunc)(std::string, void*);
typedef std::pair<CreatorFunc, ProcessorFunc> Entry;
std::map< std::string, Entry > processors;
Adding a new class is as simple as
processors["SomeClass"] = Entry(creator<SomeClass>, ClassFourMessageProcessor);

Here's one take:
For each class, create a createInsrance() function (not a method) that instantiate an instance and return a pointer cast to void*. Note this function is not part of the class - just a plain function.
Maintain a map of string to function pointer to createInstance type function.
"Register" each of the relevant classes in the map - add the string-function pointer pair to the map.
Now the generic create will search for the string in the map and invoke the specific createInstane, returning the new instance's ptr.
Now you made no changes to the classes, and can add more classes without reprogramming the factory.
You may probably put at least #1 as a template - be sure to make the compiler instantiate the specific implementation.

maybe the following aproach with a lookup table will be a nice solution.
(Note: I don't know wich compiler are you using, so this solution is for c++03, you could take unordered_map instead map if you are using a compiler with c++11 support)
(Note 2: You could use smart pointers too, and take care of the returns values, whit this example I only wants to show an aproach)
#include <iostream>
#include <string>
#include <map>
#include <vector>
struct ClassMaker
{
virtual void* getInstance() const = 0;
virtual ~ClassMaker() {}
};
class Factory
{
private:
std::map<std::string, ClassMaker*> lookupTable;
typedef typename std::map<std::string, ClassMaker*>::iterator Iterator;
public:
void addClass(const std::string& key, ClassMaker* const newClassMaker)
{
lookupTable[key] = newClassMaker;
}
void* create(const std::string& key)
{
void* result = NULL;
Iterator it = lookupTable.find(key);
if(it != lookupTable.end())
result = (it->second)->getInstance();
return result;
}
void releaseTable()
{
for (Iterator it = lookupTable.begin(); it != lookupTable.end(); ++it)
delete it->second;
}
};
struct IntCreator : public ClassMaker
{
void* getInstance() const
{
return new int;
}
};
struct StringCreator : public ClassMaker
{
void* getInstance() const
{
return new std::string;
}
};
int main()
{
Factory myFactory;
myFactory.addClass("int", new IntCreator);
myFactory.addClass("string", new StringCreator);
int* myInt = reinterpret_cast<int*>(myFactory.create("int"));
*myInt = 10;
std::cout<< *myInt << std::endl;
delete myInt;
myFactory.releaseTable();
return 0;
}

Would you consider Boost.MPL? Unlike STL, it allows creation of containers containing types, not instances. Having a map from string to a type would give you desired factory, isn't it?

Related

Dynamically instantiate a structure whose name is being stored in a string - C++

I have a string variable which contains the name of the structure. This structure is declared in a header file. I would like to create an object of a structure based on the value of the structure name which is held in the string variable in C++.
struct myStruct{
int a;
char b;
};
string structName = "myStruct";
// Instantiate a structure variable [like this: "struct myStruct"]
Could anyone please help me with this?
The feature you're looking for is called introspection. This is something C++ has not. So you should fallback to, in this order:
Question your design
Write a hack
Here's an idea of a hack:
using result_type = /* some type, possibly void */;
std::unique_ptr<result_type> factory(std::string const& kind)
{
if (kind == "alice") return new alice;
if (kind == "bob") return new bob;
// ...
return nullptr;
}
It is not possible in C++ to create an instance of a class by name determined at runtime. C++ has very little ability to reflect.
You could however build the support for it yourself. The idea here is to create a map of name-string to a factory function which returns an instance of that type. The returned instance needs to be wrapped within std::any because C++ - as a strongly and statically typed language - cannot let the return type to be determined at runtime.
There is a function add_factory, which must be called for all types that you want to be able to instantiate using the name. There is also a helper macro, which like all macros, works because of magic.
auto& factories() {
static std::unordered_map<std::string, std::any(*)()> factories;
return factories;
}
template<class T>
void
add_factory(const char* name) {
// further development: take function as argument so that
// non-default-constructible classes can be supported
factories()[name] = []() -> std::any {
return T{};
};
}
std::any
create(const char* name)
{
const auto& f = factories();
if (f.find(name) != f.end())
return f.find(name)->second();
throw std::runtime_error("I haven't heard of this type");
}
// don't use this macro in header files
#define ADD_FACTORY(name) namespace { auto dummy_##name = (add_factory<name>(#name), 0); }
// ----- usage -----
struct a {
int i;
};
ADD_FACTORY(a)
struct b {
double d;
};
ADD_FACTORY(b)
// factories are not limited to classes
ADD_FACTORY(int)
int main()
{
std::any instance = create("a");
assert(std::any_cast<a>(&instance));
}

Subclass lookup table

I have a very simple C++ lookup table for dispatching commands:
template <class T> Action* CreateAction(Command *c)
{
return new T(c);
}
typedef Action* CreateActionFunc(Command *c);
typedef struct ActionTable {
string name;
CreateActionFunc *func;
} ActionTableEntry;
vector<ActionTableEntry> GlobalActionTable = {
{ "quit" , &CreateAction<DoQuit> },
};
This works fine, but I would rather have my CreateAction function construct the new object on the stack and return it by value. But when I write this:
template <class T> T CreateAction(Command *c)
{
return T(c);
}
typedef Action CreateActionFunc(Command *c);
Then the program will no longer compile. First I get an error that an abstract class cannot be instantiated (on the typedef line) and also an error that the initialization list for the table doesn't match the type of the vector.
There is a very similar question here but every answer uses new in the factory methods, which is explicitly what I'm trying to avoid. How can this be done?
You can't use polymorphism with objects by value.
Need to be pointers or reference.
I'm guessing here you have an Action interface (so an abstract class), so you can't create an object of this dynamic type. All you can do is send a pointer of type Action with a dynamic type of a Derived Class (so what you are already doing i assume).
You could create a value object of a derived type on the stack and return a reference on the Base class and still use polymorphism, but then you'll need to address the lifetime of the Derived object problem.
The Action sub class has more information than the Action class itself - pointers to a table of it's member function, data members etc. There's not enough memory to hold this information if you return by value. Something called slicing would occur.
This answer explains it better.
How about doing something like this instead:
class Action {
void do_something(Command& params) = 0;
};
class SayHello {
void do_something(Command& params) { std::cout << "Hi!" << std::endl; }
}
class SayBye {
void do_something(Command& params) { std::cout << "Goodbye." << std::endl; }
}
.....
SayHello hello;
SayBye bye;
Quit quit;
std::map<string, Action&> action_table = {
{"hello", hello},
{"bye", bye},
{"quit", quit},
};
....
Action& getAction(Command* command) {
...;
return action_from_map;
}
This creates the action once, and returns them by reference.
What about something simple like this?
std::map<string, std::function<void(CommandArgs const&)>> action_table =
{
{"hello", [](CommandArgs const& args) { /* do something */ }},
};

How to expose fields of a class by name

I want to define structs to hold various application parameters:
struct Params
{
String fooName;
int barCount;
bool widgetFlags;
// ... many more
};
but I want to be able to enumerate, get and set these fields by name, eg so that I can expose them to automation APIs and for ease in serialisation:
Params p;
cout << p.getField("barCount");
p.setField("fooName", "Roger");
for (String fieldname : p.getFieldNames()) {
cout << fieldname << "=" << p.getField(fieldName);
}
Is there a good way of defining a binding from a string label to a get/set function? Along the lines of this (very much pseudocode):
Params() {
addBinding("barCount", setter(&Params::barCount), getter(&Params::barCount));
...
I know that other options are to auto-generate the struct from an external metadata file, and another is to store the struct as a table of (key,value) pairs, but I would rather keep the data in a struct.
I do have a Variant type which all fields are convertible to.
C++ doesn't have reflection so this isn't something you can do cleanly. Also, by referring to members as strings, you have to try to side-step the strongly typed nature of the language. Using a serialization library like Boost Serializer or Google Protobuf might be more useful.
That said, if we allow some horribleness, one could do something with an XMacro. (Disclaimer: I wouldn't recommend actually doing this). First you put all the information you need into a macro
#define FIELD_PARAMS \
FIELD_INFO(std::string, Name, "Name") \
FIELD_INFO(int, Count, "Count")
Or alternatively into a header file
<defs.h>
FIELD_INFO(std::string, Name, "Name") \
FIELD_INFO(int, Count, "Count")
Then you'll define FIELD_INFO inside your class to either mean the member declaration, or adding them to a map
struct Params{
Params() {
#define FIELD_INFO(TYPE,NAME,STRNAME) names_to_members.insert(std::make_pair(STRNAME,&NAME));
FIELD_PARAMS
#undef FIELD_INFO
}
template <typename T>
T& get(std::string field){
return *(T*)names_to_members[field];
}
std::map<std::string, void*> names_to_members;
#define FIELD_INFO(TYPE,NAME,STRNAME) TYPE NAME;
FIELD_PARAMS
#undef FIELD_INFO
};
And then you could use it like this
int main (int argc, char** argv){
Params myParams;
myParams.get<std::string>("Name") = "Mike";
myParams.get<int>("Count") = 38;
std::cout << myParams.get<std::string>("Name"); // or myParams.Name
std::cout << std::endl;
std::cout << myParams.get<int>("Count"); // or myParams.Count
return 0;
}
Unfortunately you still need to tell the compiler what the type is. If you have a good variant class and libraries that play well with it, you may be able to get around this.
I'm using a slightly different storage for this: here. The tags I use are ints for some reason, but you could use std::string keys just as well.
There is no really good way (with "good" being a very subjective aspect anyway), because whatever technique you choose is not part of the C++ language itself, but if your goal is serialisation, have a look at Boost Serialization.
I've managed to come up with something that satisfies my particular need. Ari's answer was closest in terms of mapping strings to references to member variables, though it relied on casting from void*. I've got something that's a bit more type-safe:
There's an interface for an individual PropertyAccessor that has a templated class derived from it which binds to a reference to a specific member variable and converts to and from the Variant representation:
class IPropertyAccessor
{
public:
virtual ~IPropertyAccessor() {}
virtual Variant getValueAsVariant() const =0;
virtual void setValueAsVariant(const Variant& variant) =0;
};
typedef std::shared_ptr<IPropertyAccessor> IPropertyAccessorPtr;
template <class T>
class PropertyAccessor : public IPropertyAccessor
{
public:
PropertyAccessor(T& valueRef_) : valueRef(valueRef_) {}
virtual Variant getValueAsVariant() const {return VariantConverter<T>().toVariant(valueRef); }
virtual void setValueAsVariant(const Variant& variant) {return VariantConverter<T>().toValue(variant); }
T& valueRef;
};
// Helper class to create a propertyaccessor templated on a type
template <class T>
static IPropertyAccessorPtr createAccessor(T& valueRef_)
{
return std::make_shared<PropertyAccessor<T>>(valueRef_);
}
The class exposing a collection can now define an ID -> PropertyAccessor and bind its values by reference:
#define REGISTER_PROPERTY(field) accessorMap.insert(AccessorMap::value_type(#field, createAccessor(field)))
class TestPropertyCollection
{
public:
typedef std::map<PropertyID, IPropertyAccessorPtr> AccessorMap;
TestPropertyCollection()
{
REGISTER_PROPERTY(stringField1);
// expands to
// accessorMap.insert(AccessorMap::value_type("stringField", createAccessor(stringField)));
REGISTER_PROPERTY(stringField2);
REGISTER_PROPERTY(intField1);
}
bool getPropertyVariant(const PropertyID& propertyID, Variant& retVal)
{
auto it = accessorMap.find(propertyID);
if (it != accessorMap.end()) {
auto& accessor = it->second;
retVal = accessor->getValueAsVariant();
return true;
}
return false;
}
String stringField1;
String stringField2;
int intField1;
AccessorMap accessorMap
};

C++ collection with variable types keyed by type

I'm making a class for lazy initialization of a bunch of objects (not totally generic, all under my control). Only one object of each type will exist. I have a linear-time implementation using std::vector and boost::any already. Hopefully it should give a better idea of what I'm talking about.
I can make the assumption that all the objects I'll want to access have
typedef boost::shared_ptr<CLASSNAME> HandleType
in their definitions and they all have a constructor that takes the ObjectProvider by reference.
class ObjectProvider {
typedef std::vector<boost::any> ContainerType;
ObjectProvider() : container() {}
public:
// this is where the relevant method is
template <class TElementType>
typename TElementType::HandleType get() {
for (ContainerType::iterator it = container.begin(); it != container.end(); ++it) {
try {
return boost::any_cast<typename TElementType::HandleType>(*it);
} catch (boost::bad_any_cast &) {}
}
// failed to find it so create it
TElementType::HandleType handle = boost::make_shared<TElementType>(*this);
container.push_back(handle);
return handle;
}
private:
ContainerType container;
};
// ----- FOR TESTING -----
class SomeObject {
public:
SomeObject(ObjectProvider &) {}
typedef boost::shared_ptr<SomeObject> HandleType;
};
int main(int argc, char** argv) {
ObjectProvider provider;
// expensive creation is done here
SomeObject::HandleType obj1 = provider.get<SomeObject>();
// expensive creation is not re-done
SomeObject::HandleType obj2 = provider.get<SomeObject>();
assert (obj1 == obj2); // pointers should point to the same object
}
Some motivation: Many of these objects (they're clients for various services) require creating additional clients of various types, but I don't want to be recreating them each time. So the goal of this class is to provide a method of caching the already-created clients.
Here is my question:
Is there a better way to do this?
In particular, is there a way to avoid the loop in get<...>() and somehow key by type? I'd love to have constant-time access instead of linear time and the current method fails to make use of the type information available for lookup.
Just for a little additional explanation of what I'm thinking, I might do something like this in Java:
Map<Class<?>, Object> objMap;
public <T> T get(Class<T> class) {
Object obj = objMap.get(class);
if (obj != null) {
return (T)obj;
} else {
T newObj = ;// fiddle with java reflection to create a new instance
objMap.put(class, newObj);
}
}
If there is only one of each type, then you can use typeid to extract a string representing the type, and use that as a key to a map or unordered_map.
//...
typedef std::map<std::string, boost::any> ContainerType;
//...
template <class TElementType>
typename TElementType::HandleType get() {
std::string name = typeid(TElementType).name();
ContainerType::iterator it = container.find(name);
if (it != container.end()) {
try {
return boost::any_cast<typename TElementType::HandleType>(it->second);
} catch (boost::bad_any_cast &) {}
}
// failed to find it so create it
TElementType::HandleType handle = boost::make_shared<TElementType>(*this);
container[name] = handle;
return handle;
}
If you want a class to be instanciate only once, you are probably looking for the design pattern singleton.
Wikipedia definition:
In software engineering, the singleton pattern is a design pattern that restricts the Instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. The concept is sometimes generalized to systems that operate more efficiently when only one object exists, or that restrict the instantiation to a certain number of objects. The term comes from the mathematical concept of a singleton.
Other links about singleton
C++ Singleton design pattern
Singleton: How should it be used
Can any one provide me a sample of Singleton in c++?
And you can find many more explanations on the internet about it.
If you are concerned about typeid() support, you can also add a class index yourself.
class SomeObject {
public:
SomeObject(ObjectProvider &) {}
typedef boost::shared_ptr<SomeObject> HandleType;
static const int ClassIndex = 0;
};
and the object provider becomes
class ObjectProvider {
typedef std::vector<boost::any> ContainerType;
public:
ObjectProvider() : container() {}
// this is where the relevant method is
template <class TElementType>
typename TElementType::HandleType get() {
int idx = TElementType::ClassIndex;
if (container.size() <= idx) {
container.resize(idx + 1);
}
// Check if object exists
if (container[idx].empty()) {
typename TElementType::HandleType handle = boost::make_shared<TElementType>(*this);
container[idx] = handle;
}
return boost::any_cast<typename TElementType::HandleType>(container[idx]);
}
private:
ContainerType container;
};
On the downside, you must make sure that different classes don't clash on the ClassIndex field.
If you want constant time access, you could create your own type-id:
class Registry
{
private:
static int get_id()
{
static int id = 0;
return id++;
}
template< typename T>
static int get_type_id()
{
const static int id = get_id();
return id;
}
std::vector<HandleType> handles;
HandleType make_handle( const Registry&r)
{
// do what you need to do to create a new handle.
}
public:
template<typename T>
HandleType get()
{
int id = get_type_id<T>();
if (id + 1 > handles.size())
{
handles.resize( id + 1, HandleType());
}
if (!handles[id])
{
handles[id] = make_handle( *this);
}
return handles[id];
}
};
EDIT: I see that I've essentially given the same answer as umlum, except that this answer also tries to automatically create a numerical id for each type.

What is the simplest way to create and call dynamically a class method in C++?

I want to fill a map with class name and method, a unique identifier and a pointer to the method.
typedef std::map<std::string, std::string, std::string, int> actions_type;
typedef actions_type::iterator actions_iterator;
actions_type actions;
actions.insert(make_pair(class_name, attribute_name, identifier, method_pointer));
//after which I want call the appropriate method in the loop
while (the_app_is_running)
{
std::string requested_class = get_requested_class();
std::string requested_method = get_requested_method();
//determine class
for(actions_iterator ita = actions.begin(); ita != actions.end(); ++ita)
{
if (ita->first == requested_class && ita->second == requested_method)
{
//class and method match
//create a new class instance
//call method
}
}
}
If the method is static then a simple pointer is enough and the problem is simple,
but I want to dynamically create the object so I need to store a pointer to class and an offset for the method and I don't know if this works (if the offset is always the same etc).
The problem is that C++ lacks reflection, the equivalent code in a interpreted language with reflection should look like this (example in PHP):
$actions = array
(
"first_identifier" => array("Class1","method1"),
"second_identifier" => array("Class2","method2"),
"third_identifier" => array("Class3","method3")
);
while ($the_app_is_running)
{
$id = get_identifier();
foreach($actions as $identifier => $action)
{
if ($id == $identifier)
{
$className = $action[0];
$methodName = $action[1];
$object = new $className() ;
$method = new ReflectionMethod($className , $methodName);
$method -> invoke($object);
}
}
}
PS: Yes I'm trying to make a (web) MVC front controller in C++.
I know I know why don't use PHP, Ruby, Python (insert your favorite web language here) etc?, I just want C++.
Perhaps you're looking for member function pointers.
Basic usage:
class MyClass
{
public:
void function();
};
void (MyClass:*function_ptr)() = MyClass::function;
MyClass instance;
instance.*function_ptr;
As stated in the C++ FAQ Lite, macros and typedefs would greatly increase readability when using member function pointers (because their syntax isn't common in code).
I wrote that stuff last hours, and added it to my collection of useful stuff. The most difficult thing is to cope with the factory function, if the types you want to create are not related in any way. I used a boost::variant for this. You have to give it a set of types you ever want to use. Then it will keep track what is the current "active" type in the variant. (boost::variant is a so-called discriminated union). The second problem is how you store your function pointers. The problem is that a pointer to a member of A can't be stored to a pointer to a member of B. Those types are incompatible. To solve this, i store the function pointers in an object that overloads its operator() and takes a boost::variant:
return_type operator()(variant<possible types...>)
Of course, all your types' functions have to have the same return type. Otherwise the whole game would only make little sense. Now the code:
#include <boost/variant.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/function_types/function_arity.hpp>
#include <boost/preprocessor/repetition.hpp>
#include <map>
#include <string>
#include <iostream>
// three totally unrelated classes
//
struct foo {
std::string one() {
return "I ";
}
};
struct bar {
std::string two() {
return "am ";
}
};
struct baz {
std::string three() const {
return "happy!";
}
};
// The following are the parameters you have to set
//
// return type
typedef std::string return_type;
// variant storing an object. It contains the list of possible types you
// can store.
typedef boost::variant< foo, bar, baz > variant_type;
// type used to call a function on the object currently active in
// the given variant
typedef boost::function<return_type (variant_type&)> variant_call_type;
// returned variant will know what type is stored. C++ got no reflection,
// so we have to have a function that returns the correct type based on
// compile time knowledge (here it's the template parameter)
template<typename Class>
variant_type factory() {
return Class();
}
namespace detail {
namespace fn = boost::function_types;
namespace mpl = boost::mpl;
// transforms T to a boost::bind
template<typename T>
struct build_caller {
// type of this pointer, pointer removed, possibly cv qualified.
typedef typename mpl::at_c<
fn::parameter_types< T, mpl::identity<mpl::_> >,
0>::type actual_type;
// type of boost::get we use
typedef actual_type& (*get_type)(variant_type&);
// prints _2 if n is 0
#define PLACEHOLDER_print(z, n, unused) BOOST_PP_CAT(_, BOOST_PP_ADD(n, 2))
#define GET_print(z, n, unused) \
template<typename U> \
static variant_call_type get( \
typename boost::enable_if_c<fn::function_arity<U>::value == \
BOOST_PP_INC(n), U>::type t \
) { \
/* (boost::get<actual_type>(some_variant).*t)(n1,...,nN) */ \
return boost::bind( \
t, boost::bind( \
(get_type)&boost::get<actual_type>, \
_1) BOOST_PP_ENUM_TRAILING(n, PLACEHOLDER_print, ~) \
); \
}
// generate functions for up to 8 parameters
BOOST_PP_REPEAT(9, GET_print, ~)
#undef GET_print
#undef PLACEHOLDER_print
};
}
// incoming type T is a member function type. we return a boost::bind object that
// will call boost::get on the variant passed and calls the member function
template<typename T>
variant_call_type make_caller(T t) {
return detail::build_caller<T>::template get<T>(t);
}
// actions stuff. maps an id to a class and method.
typedef std::map<std::string,
std::pair< std::string, std::string >
> actions_type;
// this map maps (class, method) => (factory, function pointer)
typedef variant_type (*factory_function)();
typedef std::map< std::pair<std::string, std::string>,
std::pair<factory_function, variant_call_type>
> class_method_map_type;
// this will be our test function. it's supplied with the actions map,
// and the factory map
std::string test(std::string const& id,
actions_type& actions, class_method_map_type& factory) {
// pair containing the class and method name to call
std::pair<std::string, std::string> const& class_method =
actions[id];
// real code should take the maps by const parameter and use
// the find function of std::map to lookup the values, and store
// results of factory lookups. we try to be as short as possible.
variant_type v(factory[class_method].first());
// execute the function associated, giving it the object created
return factory[class_method].second(v);
}
int main() {
// possible actions
actions_type actions;
actions["first"] = std::make_pair("foo", "one");
actions["second"] = std::make_pair("bar", "two");
actions["third"] = std::make_pair("baz", "three");
// connect the strings to the actual entities. This is the actual
// heart of everything.
class_method_map_type factory_map;
factory_map[actions["first"]] =
std::make_pair(&factory<foo>, make_caller(&foo::one));
factory_map[actions["second"]] =
std::make_pair(&factory<bar>, make_caller(&bar::two));
factory_map[actions["third"]] =
std::make_pair(&factory<baz>, make_caller(&baz::three));
// outputs "I am happy!"
std::cout << test("first", actions, factory_map)
<< test("second", actions, factory_map)
<< test("third", actions, factory_map) << std::endl;
}
It uses pretty fun techniques from boost preprocessor, function types and bind library. Might loop complicated, but if you get the keys in that code, it's not much to grasp anymore. If you want to change the parameter count, you just have to tweak variant_call_type:
typedef boost::function<return_type (variant_type&, int)> variant_call_type;
Now you can call member functions that take an int. Here is how the call side would look:
return factory[class_method].second(v, 42);
Have fun!
If you now say the above is too complicated, i have to agree with you. It is complicated because C++ is not really made for such dynamic use. If you can have your methods grouped and implemented in each object you want create, you can use pure virtual functions. Alternatively, you could throw some exception (like std::runtime_error) in the default implementation, so derived classes do not need to implement everything:
struct my_object {
typedef std::string return_type;
virtual ~my_object() { }
virtual std::string one() { not_implemented(); }
virtual std::string two() { not_implemented(); }
private:
void not_implemented() { throw std::runtime_error("not implemented"); }
};
For creating objects, a usual factory will do
struct object_factory {
boost::shared_ptr<my_object> create_instance(std::string const& name) {
// ...
}
};
The map could be composed by a map mapping IDs to a pair of class and function name (the same like above), and a map mapping that to a boost::function:
typedef boost::function<my_object::return_type(my_object&)> function_type;
typedef std::map< std::pair<std::string, std::string>, function_type>
class_method_map_type;
class_method_map[actions["first"]] = &my_object::one;
class_method_map[actions["second"]] = &my_object::two;
Calling the function would work like this:
boost::shared_ptr<my_object> p(get_factory().
create_instance(actions["first"].first));
std::cout << class_method_map[actions["first"]](*p);
Of course, with this approach, you loose flexibility and (possibly, haven't profiled) efficiency, but you greatly simplify your design.
I think the most important thing to find out here is, do all of your methods have the same signature? If they do, this is a trivial use of boost bind(if you're into that), functors are an option(the static, duck type kind), or just plain ole virtual inheritance is an option. Inheritance isnt currently in vogue but its pretty easy to understand and I dont think it complicates things anymore then using boost bind(imho best for small non systemic functors).
here is a sample implementation
#include<iostream>
#include<map>
#include<string>
using std::map;
using std::string;
using std::cout;
using std::pair;
class MVCHandler
{
public:
virtual void operator()(const string& somekindofrequestinfo) = 0;
};
class MyMVCHandler : public MVCHandler
{
public:
virtual void operator()(const string& somekindofrequestinfo)
{
cout<<somekindofrequestinfo;
}
};
void main()
{
MyMVCHandler myhandler;
map<string, MVCHandler*> handlerMap;
handlerMap.insert(pair<string, MVCHandler*>("mysuperhandler", &myhandler));
(*handlerMap["mysuperhandler"])("somekindofrequestdata");
}
Like many C++ questions, this looks like another application of Boost. You basically want to store the result of boost::bind(&Class::member, &Object). [edit] Storing such a result is easy with boost::function.
You can try using factory or abstract factory design patterns for the class, and a function pointer for the function.
I found the following 2 web pages with implementations when I was searching for solutions for a similar problem:
Factory
Abstract factory
If you do not want to use member function pointers, you can use statics which take an argument of the class instance. For example:
class MyClass
{
public:
void function();
static void call_function(MyClass *instance); // Or you can use a reference here.
};
MyClass instance;
MyClass::call_function(&instance);
This requires more work on the coder and causes maintainability issues (since if you update the signature of one, you must update that of the other as well).
You could also use a single static function which calls all your member functions:
class MyClass
{
public:
enum Method
{
fp_function,
};
void function();
static void invoke_method(MyClass *instance, Method method); // Or you can use a reference here.
};
void MyClass::invoke_method(MyClass *instance, Method method)
{
switch(method)
{
default:
// Error or something here.
return;
case fp_function:
instance->function();
break;
// Or, if you have a lot of methods:
#define METHOD_CASE(x) case fp_##x: instance->x(); break;
METHOD_CASE(function);
#undef METHOD_CASE
}
// Free logging! =D
}
MyClass instance;
MyClass::invoke_method(instance, MyClass::fp_function);
You can also use dynamic loading of the functions:
Use GetProcAddress in Windows, and dlsym in Unix.
Go for Subject-Observer design pattern.