Click here to Skip to main content
15,880,608 members
Articles / Programming Languages / C++11
Tip/Trick

A General C++ Reflection Engine Based on C++11 and Meta Programming

Rate me:
Please Sign up or sign in to vote.
4.92/5 (12 votes)
28 Jun 2016Apache2 min read 42.9K   881   32   22
This is a cross-platform general C++ engine, including a general runtime and a reflection engine.

Introduction

This general C++ engine is a cross-platform general C++ engine, including a general runtime and a reflection engine by now. Its main purpose is to provide reflection capabilities to C++ language. Based on C++11 and Meta Programming, this reflection engine implements a serial of general reflection functionalities for C++.

Background

As we all know, C++ RTTI has very limited ability to make reflection, which definitely becomes more and more important in modern programming. So it’s quite critical to improve the reflection ability for C++. Unfortunately, we cannot add reflection ability to C++ implictly, except creating a brand new compiler. So we have to reflect by adding macros without new compiler. Fortunately, C++11 and Meta Programming provide very easy ways to explore reflection.

Features

  • Examine normal and static fields
  • Examine methods
  • Set and get field values without including any exact definition
  • Invoke normal, virtual and static methods and get return value dynamically
  • Examine class inheritance dynamically
  • Create instance without any header files
  • Support template class reflection as well
  • Serialization for complex object

Compilers and Platforms

  • Linux: g++ version 4.8.3 or higher, 64-bit
  • Windows: Microsoft Visual Studio 2010 or higher

C++ 11 features required for compiler:

  • Auto and nullptr keyword
  • Lambda expression
  • Default template type
  • Right value reference
  • Template traits

Builds

For g++:

  • gce/trunk/builds/so/make.sh  -> libgcrt.so libreflect.so

For Visual Studio:

  • gce/trunk/builds/dll/gcrt/gcrt.vcxproj
  • gce/trunk/builds/dll/reflect/reflect.vcxproj

Using the Code

It’s quite easy to use gce::reflection.

Demo

C++
#include <src/reflect/reflect.h>
#include <stdio.h>
#include <string>

//must inherit from gce::reflection::reflectable
class Base : public gce::reflection::reflectable<Base>
{
protected:
       //declare reflectable property
       member(unsigned long long, length);
       //declare reflectable property with mutable key word
       member_mutable(std::string, name);
       //declare reflectable property as array, with size 10
       member_array(char, buf1, 10);
       //declare reflectable property as array, with size 10 and mutable key word
       member_array_mutable(char, buf2, 10);
       //declare reflectable static property
       member_static(int, level);
       //declare reflectable static property as array, with size 10
       member_static_array(double, ds, 10);

public:
       //declare and implement reflectable method
       method(void, set_length, (long long l))
       {
           length = l;
       }

       //declare and implement reflectable method
       method(void, set_name, (const std::string& str))
       {
           name = str;
       }

       //declare and implement reflectable method
       method(unsigned long long, get_length, ())
       {
           return length;
       }

       //declare reflectable method
       method(std::string, get_name, ());

       //declare and implement reflectable static method
       method(static int, get_level, ())
       {
           return level;
       }

       //declare and implement reflectable virtual method
       method(virtual void, do_something, ())
       {
           std::cout<<"Base class do_something invoked"<<std::endl;
       }   

       //pointer and reference as parameters or return value
       method(std::string*, func1, (std::string* str, int& val))
       {
           std::cout<<"str:"<<*str<<" 
           val:"<<val<<std::endl;
           return str;
       }

       //std::shared_ptr as return value
       method(std::shared_ptr<std::string>, func2, ())
       {
           return std::shared_ptr<std::string>
           (new std::string("hello, shared_ptr"));
       }
};

//define static property
int Base::level = 0;
double Base::ds[10];

//implement reflectable method out of its class body
std::string Base::get_name()
{
    return name;
}

int main()
{
       Base base;
       //get the class of Base
       auto& base_class = base.get_class();
       //print the class name
       std::cout<<"class name:"<<base_class.get_name()<<std::endl;
       //print the class size
       std::cout<<"size:"<<base_class.get_size()<<std::endl;

       //list all properties
       auto& members = base_class.members();
       std::cout<<"property list:"<<std::endl;
       for(auto it=members.begin(); it!=members.end(); ++it)
       {
              auto& member_class = it->second.get_class();
              //must use get_total_size here
              std::cout<<it->first<<", 
              type name:"<<member_class.get_name()<<", 
              size:"<<member_class. get_total_size()<<std::endl;
       }

       try //try-catch is required
       {
              //invoke method, we need to specify the return type as template type.
              //numeric 10 refers to int implicitly, 
              //so this argument must be specified unsigned long long explicitly
              base_class.get_method("set_length").invoke<void>(&base, (unsigned long long)10);
              std::string name = "Tom";
              base_class.get_method("set_name").invoke<void, Base, std::string>(&base, name);

              //invoke method and print return value
              std::cout<<"invoke get_length:"<<base_class.get_method
              ("get_length").invoke<unsigned long long>(&base)<<std::endl;
              std::cout<<"invoke get_name:"<<base_class.get_method
              ("get_name").invoke<std::string>(&base)<<std::endl;

              std::string str = "string pointer";
              int val = 10;
              //return type is string pointer
              std::cout<<"invoke func1:"<<*base_class.get_method
              ("func1").invoke<std::string*>(&base, &str, val)<<std::endl;
              //return type is std::shared_ptr<std::string>
              std::cout<<"invoke func2:"<<*base_class.get_method
              ("func2").invoke<std::shared_ptr<std::string> >(&base)<<std::endl;

              //invoke static method, instead of passing instance, 
              //we just need to pass nullptr, which must be interpreted to Base type explicitly.
              std::cout<<"invoke static get_level:"<<base_class.get_method
              	("get_level").invoke<int>((Base*)nullptr)<<std::endl;
       }
       catch(std::exception& e)
       {
              std::cout<<e.what()<<std::endl;
       }
       return 0;
}

The outputs of this program would be:

There are a few more demo codes to show what this engine provides:

  • Demo 2 (dynamic invoke)
  • Demo 3 (single inheritance)
  • Demo 4 (multiple inheritances, i.e., diamond hierarchy)
  • Demo 5 (template class)
  • Demo 6 (dynamical instance)
  • Demo 7 (serialization)

For more details and demo codes, please download the release file and document.

This release is a beta version, any problems or feedback are very welcome.

Thanks very much!

Bug History

According to the bug reports, here's the list of the bug fixing history. Please make sure to download the latest version. Thanks!

version 0.53:

fix '__call_constructor’ was not declared in this scope

fix name conflict

version 0.51:

fix demo code

 

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0


Written By
Founder
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionCompilation error Pin
bram0516-Jun-16 23:00
bram0516-Jun-16 23:00 
AnswerRe: Compilation error Pin
JohnX201517-Jun-16 6:22
JohnX201517-Jun-16 6:22 
QuestionError C2872 while compiling? Pin
bosfan16-Jun-16 5:26
bosfan16-Jun-16 5:26 
Hi,
thanks for sharing your work with us, i receive an error on line 20 in ref_parser.h:
C++
template<typename T>
struct ref : public T, virtual public gce::reflection::reflectable<struct ref<T> >


JavaScript
error C2872: 'ref' : ambiguous symbol


Can you help me with this issue?

Best regards, bosfan
AnswerRe: Error C2872 while compiling? Pin
JohnX201516-Jun-16 5:55
JohnX201516-Jun-16 5:55 
AnswerRe: Error C2872 while compiling? Pin
JohnX201516-Jun-16 7:29
JohnX201516-Jun-16 7:29 
GeneralRe: Error C2872 while compiling? Pin
bosfan5-Aug-16 4:32
bosfan5-Aug-16 4:32 
QuestionGood Article Pin
Jörg Dentler11-May-16 22:08
professionalJörg Dentler11-May-16 22:08 
AnswerRe: Good Article Pin
JohnX201512-May-16 5:18
JohnX201512-May-16 5:18 
GeneralRe: Good Article Pin
Jörg Dentler12-May-16 20:02
professionalJörg Dentler12-May-16 20:02 
GeneralRe: Good Article Pin
JohnX201513-May-16 8:19
JohnX201513-May-16 8:19 
QuestionExplicit Reflection Pin
Andy Hoffmeyer3-May-16 2:45
Andy Hoffmeyer3-May-16 2:45 
AnswerRe: Explicit Reflection Pin
JohnX20153-May-16 7:50
JohnX20153-May-16 7:50 
GeneralRe: Explicit Reflection Pin
Member 1142391617-Jun-16 8:45
Member 1142391617-Jun-16 8:45 
GeneralRe: Explicit Reflection Pin
JohnX201517-Jun-16 13:33
JohnX201517-Jun-16 13:33 
GeneralRe: Explicit Reflection Pin
BrainlessLabs.com28-Jun-16 23:43
BrainlessLabs.com28-Jun-16 23:43 
GeneralRe: Explicit Reflection Pin
JohnX201529-Jun-16 5:33
JohnX201529-Jun-16 5:33 
GeneralRe: Explicit Reflection Pin
BrainlessLabs.com29-Jun-16 22:23
BrainlessLabs.com29-Jun-16 22:23 
GeneralRe: Explicit Reflection Pin
JohnX201530-Jun-16 5:33
JohnX201530-Jun-16 5:33 
GeneralRe: Explicit Reflection Pin
BrainlessLabs.com30-Jun-16 20:41
BrainlessLabs.com30-Jun-16 20:41 
GeneralRe: Explicit Reflection Pin
JohnX20151-Jul-16 5:13
JohnX20151-Jul-16 5:13 
AnswerFormat issues.. Pin
Afzaal Ahmad Zeeshan31-Aug-15 7:09
professionalAfzaal Ahmad Zeeshan31-Aug-15 7:09 
GeneralRe: Format issues.. Pin
JohnX201531-Aug-15 7:53
JohnX201531-Aug-15 7:53 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.