Setting data members with generic setter - c++

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*

Related

Combining typesafe code with runtime decisions

I am in the process of rewriting some existing code - where previously, all answer information was stored in a string array in memory. Based on the datatype, the data was transformed in various places. Below is a quick mock up of the setup I am aiming for. Essentially you have some questions - and the structure of the answers stored in the database depends on the datatype. Generally I avoid dealing with void*, and casting them to an appropriate type - but I couldn't find a better solution that would allow me to run generic code (by means of lambdas), or be specific if the datatype is known. Templated classes won't help in this case, as all the answers need to be stored in the same vector (as some arithmetic are applied to all answers based on predefined rules).
Any advice is appreciated.
#include <vector>
#include <memory>
struct AddressData
{
wchar_t Line1[50];
wchar_t Line2[50];
long CountrySeqNo;
AddressData()
{
memset(this, 0, sizeof(*this));
};
};
struct GenericData
{
wchar_t value[200];
GenericData()
{
memset(this, 0, sizeof(*this));
};
};
enum class DataType
: short
{
GENERIC,
ADDRESS
};
class AnswerBase
{
protected:
const void* const data;
const DataType dataType;
protected:
AnswerBase(const DataType datatype, const void* const _data)
: dataType(datatype), data(data)
{
if (data == nullptr)
throw std::exception("Data may not be initialized as NULL");
};
public:
/*
Some generic methods here that would apply logic by means of lambdas etc - these would be overwritten in the derived classes
*/
template<typename T> const T& GetData() { static_assert(false, "The given type is not supported"); };
template<>
const GenericData& GetData()
{
if (DataType::GENERIC != dataType)
throw std::exception("The requested type does not match the value that initialised data");
return *static_cast<const GenericData* const>(data);
};
template<>
const AddressData& GetData()
{
if (DataType::ADDRESS != dataType)
throw std::exception("The requested type does not match the value that initialised data");
return *static_cast<const AddressData* const>(data);
};
};
class AddressAnswer
: public AnswerBase
{
public:
AddressAnswer()
: AnswerBase(DataType::ADDRESS, &answer)
{
};
protected:
AddressData answer;
};
class GenericAnswer
: public AnswerBase
{
public:
GenericAnswer()
: AnswerBase(DataType::GENERIC, &answer)
{
};
protected:
GenericData answer;
};
int main()
{
std::vector<std::shared_ptr<AnswerBase>> answers;
answers.push_back(std::make_shared<GenericAnswer>());
answers.push_back(std::make_shared<AddressAnswer>());
// In some parts of code - interact with generic methods without needing to check the underlying data type
// ....
// ....
// In parts of code where we know we are dealing with a given type - like saving to a DB
auto val1 = answers[0]->GetData<GenericData>().value;
auto val2 = answers[1]->GetData<AddressData>().Line1;
// this will give a runtime failure
//auto val3 = answers[0]->GetData<AddressData>().Line1;
return 0;
}
variant is the clean way to do this. Store it in the parent.
Alternatively, provide a variant<A,B> GetData() in the parent. Now visiting is encapsulated in the variant returned. The parent stores the data.
Alternatively, provide a virtual variant<A,B> GetData() = 0. The child type returns the data, either A or B, in the variant in question.
Alternatively, write virtual A* GetA() = 0; virtual B* GetB() = 0;. Then maybe write a template method called GetData<T> such that GetData<A>() calls GetA, etc.
Alternatively, write virtual A* Get(tag_t<A>) = 0; virtual B* Get(tag_t<B>)=0;, where
template<class T>
struct tag_t {
using type=T;
constexpr tag_t(){}
};
template<class T>
constexpr tag_t<T> tag{};
is a tag used for dispatching. Now you can call the right virtual interface by doing a Get(tag<AddressData>).
In these virtual cases, the data is stored in the derived type.

Accessing derived class' member functions in base template function

I have a class called DBDriver that handles communication with a given table in a database. Its public entry point is a function template called execute_query(), which executes SELECT queries. Upon calling this function, some database logic is performed, and then a provided container (of the template type) is populated with results. This looks something like the following:
class DBDriver {
...
template <typename CONT_T>
void execute_query(const std::string& query, CONT_T& container);
...
};
template <typename CONT_T>
void DBDriver::execute_query(const std::string& query, CONT_T& container) {
DBCursor& cursor = ... // some database logic here
populate_container(container, cursor);
}
Of course, the above will not compile, as populate_container() is not defined in DBDriver.
DBDriver should be purely virtual and have several classes derive from it (one for each database table involved). Each derived class will define its own overloads of populate_container(), one for each relevant container type. This will look something like the following:
class SampleTableDBDriver : public DBDriver {
// ...
populate_container(const ContainerTypeOne& container, DBCursor& cursor);
populate_container(const ContainerTypeTwo& container, DBCursor& cursor);
// ...
};
My original attempt at this was unsuccessful, as I would have needed to define a virtual function template in DBDriver to serve as an entry point to a derived class' populate_container() overloads. (Of course such a thing does not exist in C++, hence my issue.)
Is there a cleaner, idiomatic solution for this type of problem?
The reason why execute_query is a template function is you need a generic container. What if you define a Interface for the container?
class IContainer
{};
Template Functions cannot be virtual. Therefore, you can use the Template Method Design Pattern.
class DBDriver
{
public:
void execute_query(const std::string& query, IContainer **_ppContainer);
{
DBCursor& cursor = ... // some database logic here
populate_container(_ppContainer, cursor);
}
virtual void populate_container(IContainer **_ppContainer, DBCursor &_dbCursor) = 0;
};
And let every derived class implement populate_container and also provide their custom Container.
class SampleTableDBDriver : public DBDriver
{
public:
class ContainerTypeOne : public IContainer
{};
void populate_container(IContainer **_ppContainer, DBCursor &_dbCursor)
{
ContainerTypeOne *pContainer = new ContainerTypeOne();
//....
(*_ppContainer) = pContainer;
}
};
SampleTableDBDriver oSampleDriver;
IContainer *pContainer = NULL;
std::string szQuery = // some query ;
oSampleDriver.execute_query(szQuery, &pContainer);
if(pContainer != NULL)
{
SampleTableDBDriver::ContainerTypeOne *pSampleDriverContainer =
dynamic_cast<SampleTableDBDriver::ContainerTypeOne*>(pContainer);
//use pSampleDriverContainer
}
Edit: For supporting multiple containers.
In your original design the populate_container seems to be overloaded in derived classes. In that case you would still pass the exact container from outside while calling execute_query.
Same thing can be done with this Template Method design. Then, you will need to decipher the type of container inside the populate_container function as follows:
New signature : int populate_container(IContainer *_pContainer, DBCursor &_dbCursor)
int populate_container(IContainer *_pContainer, DBCursor &_dbCursor)
{
if(dynamic_cast<ContainerTypeOne *>(_pContainer) != NULL)
{
ContainerTypeOne *pContainerOne = _pContainer;
//populate the result by using pContainerOne
return 1;
}
if(dynamic_cast<ContainerTypeTwo *>(_pContainer) != NULL)
{
ContainerTypeOne *pContainerTwo = _pContainer;
//populate the result by using pContainerTwo
return 1;
}
//no, I do not support the container you passed.
return 0;
}
SampleTableDBDriver oSampleDriver;
SampleTableDBDriver::ContainerTypeOne oSampleContainerTypeOne;
std::string szQuery = // some query ;
if(oSampleDriver.execute_query(szQuery, &oSampleContainerTypeOne) != 0)
{
//use oSampleContainerTypeOne;
}
You have options to choose from:
If you don't need populate_container() to be a member of DBDriver and can extend (or define) container interface, just implement
ContainerTypeOne::populate(DBCursor& cursor);
Make populate_container() a friend (in case you need access to private members of DBDriver):
template <typename CONT_T> friend void execute_query(const std::string& query, CONT_T& container);
Make populate_container() a non-member template function (if you don't need access to private members of DBDriver)
One way to do this is to employ the separation of concerns principle.
Querying databases goes to its own class hierarchy, and populating container goes to its own separate class hierarchy. These two hierarchies know nothing about each other, e.g. DBDriverThirteen knows nothing about ContainerFortyTwo. The two hierarchies only touch at their roots, i.e. DBDriver (and so its every derived class) knows about IContainerPopulator but nothing about any specific containers.
You may have a template that builds a specific ContainerPopulator for each container type. Assume for simplicity that you only need to support standard containers of strings that implement push_back.
struct IContainerPopulator {
virtual void push_back(const std::string&) = 0;
};
template <class CONT_T>
struct ContainerPopulator : IContainerPopulator {
StandardContainerPopulator (CONT_T& cont) : cont(cont) {}
void push_back(const std::string& s) override { cont.push_back(s); }
private:
CONT_T& cont;
};
Now you can do this
template <typename CONT_T>
void execute_query(const std::string& query, CONT_T& container) {
execute_query_adapted(query, ContainerPopulator<CONT_T>(container));
}
// no template!
virtual void execute_query_adapted(const std::string&,
IContainerPopulator&&) = 0;
By now you have probably recognised that IContainerPopulator is nothing but a specialised poor man's function binder. Why write another one if we have pretty good support in the language and its standard library? If you only need to support push_back, you can alternatively do this:
template <typename CONT_T>
void execute_query(const std::string& query, CONT_T& container) {
execute_query_adapted2(query,
[&](const std::string& s){container.push_back(s);});
}
// no template
virtual void execute_query_adapted2(const std::string&,
std::function<void(const std::string&)>) = 0;
Now if you need more than just push_back (or any fixed set of functions) and/or more than std::string (or any fixed set of types), things can get really hairy. More information would be needed about potential implementations of populate_query.
As long as you don't mind using RTTI (or Boost.TypeIndex, which doesn't require RTTI), you can use type erasure and void* to get what you want. It's a bit dirty, but it does the job.
#include <functional>
#include <typeindex>
#include <unordered_map>
class driver {
public:
template <typename Container, typename Populator>
void register_populator(Populator populator) {
populators[type_index<Container>()] = [populator](void* v) {
Container& container = *static_cast<Container*>(v);
populator(container);
};
}
template <typename Container>
void execute(Container& container) {
auto it = populators.find(type_index<Container>());
if (it != populators.end()) {
it->second(&container);
}
}
private:
template <typename T>
static std::type_index type_index() {
return std::type_index(typeid(std::remove_cv_t<T>));
}
std::unordered_map<std::type_index, std::function<void (void*)>> populators;
};
Then use like so:
#include <vector>
#include <iostream>
int main() {
driver d;
d.register_populator<std::vector<int>>([](std::vector<int>&) {
std::cout << "Populate vector<int>\n";
});
d.register_populator<std::vector<float>>([](std::vector<float>&) {
std::cout << "Populate vector<float>\n";
});
std::vector<int> int_vector;
std::vector<float> float_vector;
d.execute(int_vector);
d.execute(float_vector);
}
Output:
Populate vector<int>
Populate vector<float>

How to associate object with its type

I'm trying to create a statistics system in C++ which will allow me to associate a string with a value of an arbitrary type. Currently, I have it working with an enum that keeps track of the type and a void * that points to the object, but this requires me to make individual if statements for all of the types I want to support. I'd like to have it so that I can support any arbitrary type using some kind of template. I've created some test code that sort of works, but there are issues:
class Test {
std::type_index type;
void *value;
public:
template <typename T>
Test(T val) : type(typeid(val)) {
T *val_p = new T;
*val_p = val;
value = (void *)val;
}
Test() : type(typeid(void)) {
value = nullptr;
}
~Test() {
//no idea how I could make this work
}
template <typename T>
T get() {
if (std::type_index(typeid(T)) == type) {
T *val_p = (T *)value;
return *val_p;
} else {
throw std::bad_typeid();
}
}
};
What I have so far works, but I don't think it would be possible to implement a destructor or copy/move constructors. The whole point is I want to store this all in a single std::unordered_map, so I can't (AFAIK) just make a template class and go from there. So, is it possible to do what I'm trying to do, and if so, how would I do it?
Based on the suggestion of GManNickG, I'm going with boost::any, as it most closely resembles what I'm looking for.
I haven't yet implemented it into the code, but the basic structure will be something along the lines of:
#include <typeinfo>
#include <boost/any.hpp>
class Statistic {
boost::any value;
public:
template <typename T>
Statistic(T val) : value(val) {}
Statistic() : value() {}
template <typename T>
bool checkType() {
return typeid(T) == value.type();
}
//Will cause an exception if the type doesn't match
//Caller should check type if unsure
template <typename T>
T get() {
if (checkType<T>()) {
return boost::any_cast<T>(value);
} else {
//throw some exception
throw bad_any_cast();
}
}
}
With this, I don't need to deal with destructors or copy/move functions, since the implicit ones will call the code already implemented by the boost library.
EDIT:
Thanks to milleniumbug for pointing out boost::any already stores the std::type_info

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?

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.