Reputation: 13257
I am trying to implement limited reflection
in C++, so that I could be able to call getter
and setter
on the objects stored. Here is what I have done so far
#ifndef REFLECTION_MANAGER_HPP_
#define REFLECTION_MANAGER_HPP_
#include <iostream>
#include <string>
template <class Owner, class IOType>
class SingleProperty {
public:
typedef IOType (Owner::*get_func_t)();
typedef void (Owner::*set_func_t)( IOType Value );
inline SingleProperty(get_func_t Getter, set_func_t Setter ): m_Getter(Getter), m_Setter(Setter) {
}
get_func_t m_Getter;
set_func_t m_Setter;
};
class ReflectionManager {
public:
static ReflectionManager& Instance() {
static ReflectionManager instance;
return instance;
}
template <class Owner, class IOType>
void RegisterProperty( std::string class_name,
std::string property_name,
typename SingleProperty<Owner, IOType>::get_func_t GetFn,
typename SingleProperty<Owner, IOType>::set_func_t SetFn) {
SingleProperty<Owner, IOType>* pProperty = new SingleProperty<Owner, IOType>(GetFn, SetFn );
m_class_memeber_map[class_name][property_name] = pProperty;
}
template <class Owner> void put(std::string key, void *value, std::string class_name = NULL ) {
Owner *ptr = reinterpret_cast<Owner*>(value);
std::map<std::string, std::map< std::string, void*> >::iterator pos = m_class_memeber_map.find(class_name);
if ( pos == m_class_memeber_map.end()) {
return; // handle the error
}
for ( std::map< std::string, void*>::iterator itr = pos->second.begin(); itr != pos->second.end(); ++itr ) {
SingleProperty<Owner,std::string> *ptr = (SingleProperty<Owner,std::string> *)itr->second;
(ptr->*m_Getter)();
}
}
private:
ReflectionManager() {
}
ReflectionManager(ReflectionManager const&);
void operator=(ReflectionManager const&);
std::map<std::string, std::map< std::string, void*> > m_class_memeber_map;
};
#endif
This will be called as follows
ReflectionManager::Instance().RegisterProperty<Person, std::string>("Person", "m_name", &Person::GetName, &Person::SetName);
ReflectionManager::Instance().RegisterProperty<Person, std::string>("Person", "m_dept", &Person::GetDept, &Person::SetDept);
ReflectionManager::Instance().RegisterProperty<Person, int>("Person", "m_age", &Person::GetAge, &Person::SetAge);
Person p1;
p1.SetName("Avinash");
p1.SetDept("Gemfire Native Client");
p1.SetAge(34);
ReflectionManager::Instance().put<Person>( "key1", &p1, "Person");
I have stored the getter
and setter
in the map
, but in put
function I am not able to call it since I donot know the type.
Basically How do i implement now the for loop for ( std::map< std::string, void*>::iterator itr = pos->second.begin(); itr != pos->second.end(); ++itr )
in which I want to iterate over each element and call the respective getter
and setter
methods.
I tried this but does not work.
(ptr->*((itr->second).m_Getter))();
Another Approach I found Would appreciate Comments
template <class Owner, class IOType>
void RegisterProperty( std::string class_name,
std::string property_name,
typename SingleProperty<Owner, IOType>::get_func_t GetFn,
typename SingleProperty<Owner, IOType>::set_func_t SetFn) {
SingleProperty<Owner, IOType>* pProperty = new SingleProperty<Owner, IOType>(GetFn, SetFn );
m_class_memeber_map[class_name][property_name] = pProperty;
m_property_type_map[class_name].push_back(std::make_pair(property_name, TypeName<IOType>::get()));
}
template <class Owner> void put(std::string key, void *value, std::string class_name = NULL ) {
Owner *pOwner = reinterpret_cast<Owner*>(value);
std::map<std::string, std::map< std::string, void*> >::iterator pos = m_class_memeber_map.find(class_name);
std::vector<std::pair<std::string, std::string> > vector_property_map = m_property_type_map.find(class_name)->second;
for ( std::vector<std::pair<std::string, std::string> >::iterator itr = vector_property_map.begin();itr != vector_property_map.end(); ++itr ) {
std::map< std::string, void*>::iterator pos_getter_setter_fn = pos->second.find(itr->first);
if ( itr->second == "int" ) {
SingleProperty<Owner,int> *ptr = (SingleProperty<Owner, int> *)pos_getter_setter_fn->second;
(pOwner->*(ptr->m_Getter))();
} else if ( itr->second == "string" ) {
SingleProperty<Owner,std::string> *ptr = (SingleProperty<Owner, std::string> *)pos_getter_setter_fn->second;
(pOwner->*(ptr->m_Getter))();
}
}
}
Upvotes: 4
Views: 301
Reputation: 9089
These pointers are pointers to function members of Owner
type:
get_func_t m_Getter;
set_func_t m_Setter;
Why do you try to call them giving SingleProperty<>
pointer as object?
Owner *ptr = reinterpret_cast<Owner*>(value);
for ( std::map< std::string, void*>::iterator itr = pos->second.begin();
itr != pos->second.end(); ++itr )
{
SingleProperty<Owner,std::string> *ptr =
(SingleProperty<Owner,std::string> *)itr->second;
// Here is the flaw, you are trying to call m_Getter from SingleProperty object
// pointer, but it must be Owner pointer!
(ptr->*m_Getter)();
}
Also you have to properly pass type of property as template parameter IOType
.
I'm not sure what do you try to do with this function and what is the effect of calling getters with discarded return type, but from abstract syntax point of view it shall be like this:
template <class Owner, class IOType> void put(const std::string& key, Owner* value,
const std::string& class_name = "")
{
std::map<std::string, std::map<std::string, void*> >::iterator pos =
m_class_memeber_map.find(class_name);
if(pos == m_class_memeber_map.end())
{
return; // handle the error
}
for(std::map<std::string, void*>::iterator itr = pos->second.begin();
itr != pos->second.end(); ++itr)
{
SingleProperty<Owner,IOType> *ptr =
static_cast<SingleProperty<Owner, IOType>*>(itr->second);
(value->*(ptr->m_Getter))(); // return IOType discarded?!?!
}
}
Upvotes: 1