Avinash
Avinash

Reputation: 13257

Kind of reflection in C++

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

Main Code

#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

Calling Code

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.

Problem

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

Answers (1)

Rost
Rost

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

Related Questions