Subclass lookup table - c++

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 */ }},
};

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

C++ Returning Multiple Types as Reference

Ok so I'm trying to setup a template method that returns a reference of an undetermined type based on a parameter request. Everything looks fine but it keeps telling me that no overloaded method of the provided template method exists when I call it. The code looks something like this:
class IObj {
public:
int id;
}
class ObjOne : public IObj {}
class ObjTwo : public IObj {}
class ObjThree : public IObj {}
enum ObjectTypes {
O1Type,
O2Type,
O3Type
}
class ObjManager {
public:
std::vector< std::unique_ptr<ObjOne> > O1Holder;
std::vector< std::unique_ptr<ObjTwo> > O2Holder;
std::vector< std::unique_ptr<ObjThree> > O3Holder;
ObjManager() {}
template <class T>
T& GetObject(int oID, ObjectTypes oType) {
if(oType == ObjectTypes::O1Type) {
for(int i = 0; i < O1Holder.size(); i++) {
if(O1Holder[i]->id == oID) {
return *O1Holder[i];
}
}
}
else if(oType == ObjectTypes::O2Type) {
for(int i = 0; i < O2Holder.size(); i++) {
if(O2Holder[i]->id == oID) {
return *O2Holder[i];
}
}
}
else if(oType == ObjectTypes::O3Type) {
for(int i = 0; i < O3Holder.size(); i++) {
if(O3Holder[i]->id == oID) {
return *O3Holder[i];
}
}
}
}
}
int main() {
std::unique_ptr<ObjManager> oManager(new ObjManager());
ObjOne& a = oManager->GetObject(0, ObjectTypes::O1Type);
return 0;
}
Everything works fine, and I can make a method that returns a reference to the object stored in the vectors if I return their specific type, but I'm trying to reduce the redundancy of making many functions to return each different type. So I wanted to make a templated method that would return an object type based on which ever type I requested.
It's not giving me any errors it just keeps underlining the -> in the expression oManager->GetObject, and tells me there is no overloaded method for the template method call. Specifically it states "no instance of function template 'ObjManager::GetObject' matches the argument list, argument types are (int, ObjectTypes)" even though I'm passing an integer and ObjectTypes:: into the function's parameter list. I've looked all over for an answer to this but have not been able to find a similar situation to draw experience on.
EDIT: Sorry should have specified that this is a precursor to a vast list of vectors, I just put 3 of them for simplicity. That's why I'm trying to make a single function that can handle the return of different types so that I don't have to make a return function for every vector I create. And the purpose of returning a reference to the specified type is because each derived type will have unique data that is not in the base class, so I'm pulling the objects for editing.
As #tobi303 commented, you should definetly use the template Parameter T in your GetObject class. Then you would actually avoid repeating yourself as the Compiler will generate the code for you that you have repeated 3 times
template <class T>
T& GetObject(int oID) {
for(int i = 0; i < OHolder<T>.size(); i++) {
if(OHolder<T>[i]->id == oID) {
return *OHolder<T>[i];
}
}
While you would have to define a OHolder Template function, too.
It is not possible to change the return type of a function based on runtime information (such as your parameters), because they are obviously unknown to the compiler.
If you will always know at compile time which object type you are going to choose, you can use a trick:
Step 1: Turn your enum into a couple of empty structs:
struct O1Type {};
struct O2Type {};
struct O3Type {};
Step 2: Instead of using else ifs, use function overloading:
ObjOne& GetObject(int oID, O1Type) {/* TODO*/}
ObjTwo& GetObject(int oID, O2Type) {/* TODO*/}
ObjThree& GetObject(int oID, O3Type) {/* TODO*/}
You can now use
ObjOne& a = oManager->GetObject(0, O1Type());
(or, even better auto& a = oManager->GetObject(0, O1Type());)
You seem to be trying to use both run-time polymorphism AND the compile-time (template) polymorphism. It doesn't work this way. You cannot return multiple types from the SAME METHOD.
What you probably want to do is to either define a method like #yussuf described, or to fully start using run-time polymorphism - in which case you don't need three containers, and the type becomes part of the object ID.
I concur with #yussuf's approach. Just do that, it probably will solve your problem.
I would also recommend to use a hash / map instead of performing linear search, but this is a different story...
Root cause
Template argument type deduction can't be solely based on the return type of the function.
On the way to a solution
You could therefore add a dummy function argument to transfer the type information:
template <class T>
T& GetObject(int oID, ObjectTypes oType, T&x) {
...
}
and in main():
ObjOne& a = oManager->GetObject(0, ObjectTypes::O1Type, a);
Then the template type can be deduced.
But this will not solve your problem. This type deduction is at compile time, so that all the possible returns of the function should return the same type (or something that can be converted to it).
This is not the case of your code, which will lead to other compilation errors (see online failure).
The solution
The only workable solution is that you determine the common denominator to return. Make the function a non-template function returning an IObj&:
IObj& GetObject(int oID, ObjectTypes oType) {
...
}
You should then manage the return object as a polymorphic obhect as well. As the return is by reference, this is fine (i.e. no slicing occurs). The returned reference will really refer to the object returned, whatever its derived type could be. But you'd have to redesign your calling code for polymorphism:
IObj& a = oManager->GetObject(0, ObjectTypes::O1Type);
Online demo
But this is somewhat clumsy because you indicate in an enum the expected type, but then end with a reference to a parent that you can't handle so easily.
Conclusion
As you indicate in the function the expected return type, you'd better go for the solution in Yussuf's rexcellent answer, but applying the technique of the dummy argument for type deduction.
Ok so after much research, I have determined the best way to accomplish this is to create a custom container class like so:
#include <vector>
#include <memory>
class Base {
public:
int ID;
Base(int id) { ID = id; }
}
class A : public Base {
public:
int X;
A(int id) : Base(id) {}
}
class B : public Base {
public:
int Y;
B(int id) : Base(id) {}
}
template <class T>
class MyContainer {
private:
std::vector<std::unique_ptr<T>> internalContainer;
public:
MyContainer() {}
~MyContainer() {}
void CreateItem(int id) {
std::unique_ptr<T> newItem(new T(id));
internalContainer.push_back(std::move(newItem));
}
T& GetItem(int id) {
for(std::vector<std::unique_ptr<T>>::iterator it = internalContainer.begin(); it!= internalContainer.end(); ++it) {
if((*it)->ID == id) {
return **it;
}
}
}
}
int main() {
MyContainer<A> AList;
MyContainer<B> BList;
AList.CreateItem(0);
BList.CreateItem(0);
A& AOne = AList.GetItem(0);
B& BOne = BList.GetItem(0);
AOne.X = 10;
BOne.Y = 20;
std::cout << std::to_string(AOne.X) << "\n";
std::cout << std::to_string(BOne.Y) << "\n";
}
Let me know your opinions on if this is acceptable or if it can be improved! :)

C++ generic object factory by string name

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?

Setting data members with generic setter

I'm trying to implement a superclass in c++ that would implement one method:
-void setValueForKey(void *value, string key);
all this method would have to do is to set the value of a property associated with a given key to the new value.
This would be easy in a language that implements introspection mechanisms; as far as I know C++ doesn't.
In order to accomplish this I created another method:
void registerKeyForProperty(void *propertyPtr, string key);
all this method does is it stores in and internal map a pointer to a property associated with a given key, so all my subclasses would call this for every property they declare and I would have a way of setting values for properties without necessity to use the setters.(That's what I need!) (I explain why at the end of the post...)
for this second function I have the following implementation:
void registerKeyForProperty(void *propertyPtr, string key){
_keysDictionary->insert(pair<string,void*>(key,property));
}
where _keysDictionary is a stl map.
for the first one I have the following implementation:
void ConstructableObject::setValueForKey(void* value, string key) {
map<string,void *>::iterator it=_keysDictionary->find(key);
if(it==_keysDictionary->end()){return;}//just return if there is nothing for that key
void *property=it->second;
(*property)=value;
}
the problem is the last line is not legal C++ because ofcourse I cannot just deference that void*.
My questions are:
Is there any other way of implementing the desired functionality?
Is there a "legal" way of doing this the way I am doing it? (I cannot simply use a reinterpret_cast cause I don't know what to cast to...)
Why this:
I need to parse and xml file that has some information about some objects. I'll be using TinyXML and therefore I'll have the atribute names for the objects and their values. That would be how I would like to use it:
MyClass obj();//the constructor would call setValueForKey(...,...) for every property so all are now registered
for every attribute{
obj.setValueForKey(attribute.value,attribute.name);
}
//all properties should be set now
If the key exists, why not simply do
_keysDictionary[key] = value;
Or if you want to use the iterator
it->second = value;
It could be done with using of the type awareness techniques and for example The Memento Pattern is one of choices. The following code could be extended with the some macro stuff that generating the unique keys based on the attribute pointer signature:
class introspection
{
public:
template <typename Class, typename Member>
void registerKey(std::string key, Member Class::*memberPointee, Class* classPointee)
{
typedef member_setter<Class, Member> hold_member_pointer;
base_setter* setter = new hold_member_pointer(memberPointee, classPointee);
keys.insert(std::make_pair(key, setter));
}
template <typename Value>
void setValue(std::string key, Value value)
{
if ( keys.count(key) > 0 )
{
keys[key]->set(value);
}
else
{
throw std::logic_error("no such key");
}
}
private:
struct base_setter
{
virtual void set(boost::any value) = 0;
}; // struct base_setter
template <typename Class, typename Member>
struct member_setter : base_setter
{
member_setter(Member Class::*memberPointee, Class* classPointee)
: memberPointee(memberPointee)
, classPointee(classPointee) {}
void set(boost::any value) override
{
Member newValue = boost::any_cast<Member>(value);
classPointee->*memberPointee = newValue;
}
Member Class::*memberPointee;
Class* classPointee;
}; // struct member_setter
std::map<std::string, base_setter*> keys;
}; // class introspection
struct Data
{
int value;
}; // struct Data
int main()
{
introspection i;
Data d;
d.value = 100;
i.registerKey("value", &Data::value, &d);
i.setValue("value", 200); // OK
i.setValue("value", "not valid"); // bad_any_cast
}
The one thing that could be (not so easily) improved here is provide the compile-time type check for setValue, instead of runtime any_cast casting.
Make setValueForKey be a templated function instead of a function that accepts a void pointer. That way, you can know about the type information of the property long enough to create a templated setter
class BaseSetter
{
public:
virtual void set(void* inValue) = 0;
}
template <typename T>
class SpecializedSetter
{
public:
SpecializedSetter(T* inMyValue)
: mValue(inValue)
{ }
virtual void set(void* inValue)
{
*mValue = *reinterpret_cast<T*>(inValue);
}
private:
T* mValue;
}
template <typename T>
void registerKeyForProperty(T* inValue, string inKey)
{
registerSetterForProperty(new SpecificSetter<T>(inValue), inKey);
}
This, however, assumes inValue is a pointer to the same type of data as the value on the class. To make that safe, consider boost::any or defining some other type which contains the type information from the XML file and using that rather than void*

Is it possible to take a type as an argument in a function?

I'm trying to write a function for a database class that is basically just a wrapper around a hash_map of objects (say shapes) indexed by ID numbers that will look up an ID and cast it to the appropriate pointer type.
e.g. I'd like to be able to do something like this:
Circle* shapeToLookup = NULL;
int idNum = 12;
database.lookup(idNum, circleToLookup);
if(circleToLookup != NULL)
{
// Do stuff with the circle.
}
and have the database know the type of its argument. Is there a way to do this without either overloading the function (lookup(int, Circle*), lookup(int, Rect*), ad nauseum)? Can you declare a function like lookup(int, Shape*) and have it know which type it's given?
Thanks!
template <T>
Database::lookup(int idNum, T TobjectToLookup)
{
// inside here, T is the type of the object passed in/
}
You can do it with a template.
Edit: new implementation based on the extra information. If mymap is a std::map<int, Shape*>:
template <typename T>
void lookup(int idNum, T* &ptr) {
auto it = mymap.find(idNum);
if (it == mymap.end()) {
ptr = 0;
} else {
ptr = dynamic_cast<T*>(*it); // Shape must have a virtual member function
}
}
Or you might prefer:
template <typename T>
T* lookup(int idNum) {
auto it = mymap.find(idNum);
if (it == mymap.end()) {
return 0;
}
return dynamic_cast<T*>(*it);
}
Then call it like Circle *circle = database.lookup<Circle>(123);
Obviously polymorphic containers are a whole heap of fun in themselves, but I'll assume you have that sorted. There may well be a shared_ptr in there somewhere that I've left out.
Old implementation when I thought the DB might store copies of POD:
template <typename T>
void lookup(int idNum, T* &ptr) {
void *theresult = // something based on idNum
// some check needed here that theresult really is the right type.
// how you do this depends on the database, but suppose that
// the database gives us some integer "type" which indicates the type
if (type != type_constant<T>::value) {
ptr = 0;
} else {
ptr = static_cast<T*>(theresult);
}
}
type_constant is an example of "type traits", you implement it like:
template <typename T>
struct type_constant {};
template <>
struct type_constant<Circle> {
static const int value = 1;
};
template <>
struct type_constant<Rectangle> {
static const int value = 2;
};
// etc...
Others have explained how to pass a type to a function (by using function templates). I'd like to give another point of view:
It might be even better to introduce a new virtual function on Shape and then move the Do stuff with the Circle part into the reimplementation of that virtual function in the Cricle class.
That way, you remove the need to know the type. You just fetch a Shape object from your database and then call a doStuff() function - and it does the right thing depending on the actual type of the Shape. A good use case for a virtual function. :-)
Of course, this might be more or less simple, depending on what Do stuff actually does.