How can I add reflection to a C++ application?

Viewed 259501

I'd like to be able to introspect a C++ class for its name, contents (i.e. members and their types) etc. I'm talking native C++ here, not managed C++, which has reflection. I realise C++ supplies some limited information using RTTI. Which additional libraries (or other techniques) could supply this information?

28 Answers

There are two kinds of reflection swimming around.

  1. Inspection by iterating over members of a type, enumerating its methods and so on.

    This is not possible with C++.
  2. Inspection by checking whether a class-type (class, struct, union) has a method or nested type, is derived from another particular type.

    This kind of thing is possible with C++ using template-tricks. Use boost::type_traits for many things (like checking whether a type is integral). For checking for the existence of a member function, use Templated check for the existence of a class member function? . For checking whether a certain nested type exists, use plain SFINAE .

If you are rather looking for ways to accomplish 1), like looking how many methods a class has, or like getting the string representation of a class id, then I'm afraid there is no Standard C++ way of doing this. You have to use either

  • A Meta Compiler like the Qt Meta Object Compiler which translates your code adding additional meta information.
  • A Framework consisting of macros that allow you to add the required meta-information. You would need to tell the framework all methods, the class-names, base-classes and everything it needs.

C++ is made with speed in mind. If you want high-level inspection, like C# or Java has, there is no way to do that without some additional effort.

And I would love a pony, but ponies aren't free. :-p

http://en.wikibooks.org/wiki/C%2B%2B_Programming/RTTI is what you're going to get. Reflection like you're thinking about -- fully descriptive metadata available at runtime -- just doesn't exist for C++ by default.

I would recommend using Qt.

There is an open-source licence as well as a commercial licence.

You need to look at what you are trying to do, and if RTTI will satisfy your requirements. I've implemented my own pseudo-reflection for some very specific purposes. For example, I once wanted to be able to flexibly configure what a simulation would output. It required adding some boilerplate code to the classes that would be output:

namespace {
  static bool b2 = Filter::Filterable<const MyObj>::Register("MyObject");
} 

bool MyObj::BuildMap()
{
  Filterable<const OutputDisease>::AddAccess("time", &MyObj::time);
  Filterable<const OutputDisease>::AddAccess("person", &MyObj::id);
  return true;
}

The first call adds this object to the filtering system, which calls the BuildMap() method to figure out what methods are available.

Then, in the config file, you can do something like this:

FILTER-OUTPUT-OBJECT   MyObject
FILTER-OUTPUT-FILENAME file.txt
FILTER-CLAUSE-1        person == 1773
FILTER-CLAUSE-2        time > 2000

Through some template magic involving boost, this gets translated into a series of method calls at run-time (when the config file is read), so it's fairly efficient. I wouldn't recommend doing this unless you really need to, but, when you do, you can do some really cool stuff.

What are you trying to do with reflection?
You can use the Boost type traits and typeof libraries as a limited form of compile-time reflection. That is, you can inspect and modify the basic properties of a type passed to a template.

I did something like what you're after once, and while it's possible to get some level of reflection and access to higher-level features, the maintenance headache might not be worth it. My system was used to keep the UI classes completely separated from the business logic through delegation akin to Objective-C's concept of message passing and forwarding. The way to do it is to create some base class that is capable of mapping symbols (I used a string pool but you could do it with enums if you prefer speed and compile-time error handling over total flexibility) to function pointers (actually not pure function pointers, but something similar to what Boost has with Boost.Function--which I didn't have access to at the time). You can do the same thing for your member variables as long as you have some common base class capable of representing any value. The entire system was an unabashed ripoff of Key-Value Coding and Delegation, with a few side effects that were perhaps worth the sheer amount of time necessary to get every class that used the system to match all of its methods and members up with legal calls: 1) Any class could call any method on any other class without having to include headers or write fake base classes so the interface could be predefined for the compiler; and 2) The getters and setters of the member variables were easy to make thread-safe because changing or accessing their values was always done through 2 methods in the base class of all objects.

It also led to the possibility of doing some really weird things that otherwise aren't easy in C++. For example I could create an Array object that contained arbitrary items of any type, including itself, and create new arrays dynamically by passing a message to all array items and collecting the return values (similar to map in Lisp). Another was the implementation of key-value observing, whereby I was able to set up the UI to respond immediately to changes in the members of backend classes instead of constantly polling the data or unnecessarily redrawing the display.

Maybe more interesting to you is the fact that you can also dump all methods and members defined for a class, and in string form no less.

Downsides to the system that might discourage you from bothering: adding all of the messages and key-values is extremely tedious; it's slower than without any reflection; you'll grow to hate seeing boost::static_pointer_cast and boost::dynamic_pointer_cast all over your codebase with a violent passion; the limitations of the strongly-typed system are still there, you're really just hiding them a bit so it isn't as obvious. Typos in your strings are also not a fun or easy to discover surprise.

As to how to implement something like this: just use shared and weak pointers to some common base (mine was very imaginatively called "Object") and derive for all the types you want to use. I'd recommend installing Boost.Function instead of doing it the way I did, which was with some custom crap and a ton of ugly macros to wrap the function pointer calls. Since everything is mapped, inspecting objects is just a matter of iterating through all of the keys. Since my classes were essentially as close to a direct ripoff of Cocoa as possible using only C++, if you want something like that then I'd suggest using the Cocoa documentation as a blueprint.

The two reflection-like solutions I know of from my C++ days are:

1) Use RTTI, which will provide a bootstrap for you to build your reflection-like behaviour, if you are able to get all your classes to derive from an 'object' base class. That class could provide some methods like GetMethod, GetBaseClass etc. As for how those methods work you will need to manually add some macros to decorate your types, which behind the scenes create metadata in the type to provide answers to GetMethods etc.

2) Another option, if you have access to the compiler objects is to use the DIA SDK. If I remember correctly this lets you open pdbs, which should contain metadata for your C++ types. It might be enough to do what you need. This page shows how you can get all base types of a class for example.

Both these solution are a bit ugly though! There is nothing like a bit of C++ to make you appreciate the luxuries of C#.

Good Luck.

I think you might find interesting the article "Using Templates for Reflection in C++" by Dominic Filion. It is in section 1.4 of Game Programming Gems 5. Unfortunately I dont have my copy with me, but look for it because I think it explains what you are asking for.

Reflection is essentially about what the compiler decided to leave as footprints in the code that the runtime code can query. C++ is famous for not paying for what you don't use; because most people don't use/want reflection, the C++ compiler avoids the cost by not recording anything.

So, C++ doesn't provide reflection, and it isn't easy to "simulate" it yourself as general rule as other answers have noted.

Under "other techniques", if you don't have a language with reflection, get a tool that can extract the information you want at compile time.

Our DMS Software Reengineering Toolkit is generalized compiler technology parameterized by explicit langauge definitions. It has langauge definitions for C, C++, Java, COBOL, PHP, ...

For C, C++, Java and COBOL versions, it provides complete access to parse trees, and symbol table information. That symbol table information includes the kind of data you are likely to want from "reflection". If you goal is to enumerate some set of fields or methods and do something with them, DMS can be used to transform the code according to what you find in the symbol tables in arbitrary ways.

The RareCpp library makes for fairly easy and intuitive reflection - all field/type information is designed to either be available in arrays or to feel like array access. It's written for C++17 and works with Visual Studios, g++, and Clang. The library is header only, meaning you need only copy "Reflect.h" into your project to use it.

Reflected structs or classes need the REFLECT macro, where you supply the name of the class you're reflecting and the names of the fields.

class FuelTank {
    public:
        float capacity;
        float currentLevel;
        float tickMarks[2];

    REFLECT(FuelTank, capacity, currentLevel, tickMarks)
};

That's all there is, no additional code is needed to setup reflection. Optionally you can supply class and field annotations to be able to traverse superclasses or add additional compile-time information to a field (such as Json::Ignore).

Looping through fields can be as simple as...

for ( size_t i=0; i<FuelTank::Class::TotalFields; i++ )
    std::cout << FuelTank::Class::Fields[i].name << std::endl;

You can loop through an object instance to access field values (which you can read or modify) and field type information...

FuelTank::Class::ForEachField(fuelTank, [&](auto & field, auto & value) {
    using Type = typename std::remove_reference<decltype(value)>::type;
    std::cout << TypeToStr<Type>() << " " << field.name << ": " << value << std::endl;
});

A JSON Library is built on top of RandomAccessReflection which auto identifies appropriate JSON output representations for reading or writing, and can recursively traverse any reflected fields, as well as arrays and STL containers.

struct MyOtherObject { int myOtherInt; REFLECT(MyOtherObject, myOtherInt) };
struct MyObject
{
    int myInt;
    std::string myString;
    MyOtherObject myOtherObject;
    std::vector<int> myIntCollection;

    REFLECT(MyObject, myInt, myString, myOtherObject, myIntCollection)
};

int main()
{
    MyObject myObject = {};
    std::cout << "Enter MyObject:" << std::endl;
    std::cin >> Json::in(myObject);
    std::cout << std::endl << std::endl << "You entered:" << std::endl;
    std::cout << Json::pretty(myObject);
}

The above could be ran like so...

Enter MyObject:
{
  "myInt": 1337, "myString": "stringy", "myIntCollection": [2,4,6],
  "myOtherObject": {
    "myOtherInt": 9001
  }
}


You entered:
{
  "myInt": 1337,
  "myString": "stringy",
  "myOtherObject": {
    "myOtherInt": 9001
  },
  "myIntCollection": [ 2, 4, 6 ]
}

See also...

If you're looking for relatively simple C++ reflection - I have collected from various sources macro / defines, and commented them out how they works. You can download header files from here:

https://github.com/tapika/TestCppReflect/blob/master/MacroHelpers.h

set of defines, plus functionality on top of it:

https://github.com/tapika/TestCppReflect/blob/master/CppReflect.h https://github.com/tapika/TestCppReflect/blob/master/CppReflect.cpp https://github.com/tapika/TestCppReflect/blob/master/TypeTraits.h

Sample application resides in git repository as well, in here: https://github.com/tapika/TestCppReflect/

I'll partly copy it here with explanation:

#include "CppReflect.h"
using namespace std;


class Person
{
public:

    // Repack your code into REFLECTABLE macro, in (<C++ Type>) <Field name>
    // form , like this:

    REFLECTABLE( Person,
        (CString)   name,
        (int)       age,
...
    )
};

void main(void)
{
    Person p;
    p.name = L"Roger";
    p.age = 37;
...

    // And here you can convert your class contents into xml form:

    CStringW xml = ToXML( &p );
    CStringW errors;

    People ppl2;

    // And here you convert from xml back to class:

    FromXml( &ppl2, xml, errors );
    CStringA xml2 = ToXML( &ppl2 );
    printf( xml2 );

}

REFLECTABLE define uses class name + field name with offsetof - to identify at which place in memory particular field is located. I have tried to pick up .NET terminology for as far as possible, but C++ and C# are different, so it's not 1 to 1. Whole C++ reflection model resides in TypeInfo and FieldInfo classes.

I have used pugi xml parser to fetch demo code into xml and restore it back from xml.

So output produced by demo code looks like this:

<?xml version="1.0" encoding="utf-8"?>
<People groupName="Group1">
    <people>
        <Person name="Roger" age="37" />
        <Person name="Alice" age="27" />
        <Person name="Cindy" age="17" />
    </people>
</People>

It's also possible to enable any 3-rd party class / structure support via TypeTraits class, and partial template specification - to define your own TypeTraitsT class, in similar manner to CString or int - see example code in

https://github.com/tapika/TestCppReflect/blob/master/TypeTraits.h#L195

This solution is applicable for Windows / Visual studio. It's possible to port it to other OS/compilers, but haven't done that one. (Ask me if you really like solution, I might be able to help you out)

This solution is applicable for one shot serialization of one class with multiple subclasses.

If you however are searching for mechanism to serialize class parts or even to control what functionality reflection calls produce, you could take a look on following solution:

https://github.com/tapika/cppscriptcore/tree/master/SolutionProjectModel

More detailed information can be found from youtube video:

C++ Runtime Type Reflection https://youtu.be/TN8tJijkeFE

I'm trying to explain bit deeper on how c++ reflection will work.

Sample code will look like for example this:

https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/testCppApp.cpp

c.General.IntDir = LR"(obj\$(ProjectName)_$(Configuration)_$(Platform)\)";
c.General.OutDir = LR"(bin\$(Configuration)_$(Platform)\)";
c.General.UseDebugLibraries = true;
c.General.LinkIncremental = true;
c.CCpp.Optimization = optimization_Disabled;
c.Linker.System.SubSystem = subsystem_Console;
c.Linker.Debugging.GenerateDebugInformation = debuginfo_true;

But each step here actually results in function call Using C++ properties with __declspec(property(get =, put ... ).

which receives full information on C++ Data Types, C++ property names and class instance pointers, in form of path, and based on that information you can generate xml, json or even serialize that one over internet.

Examples of such virtual callback functions can be found here:

https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/VCConfiguration.cpp

See functions ReflectCopy, and virtual function ::OnAfterSetProperty.

But since topic is really advanced - I recommend to check through video first.

If you have some improvement ideas, feel free to contact me.

You can achieve cool static reflection features for structs with BOOST_HANA_DEFINE_STRUCT from the Boost::Hana library.
Hana is quite versatile, not only for the usecase you have in mind but for a lot of template metaprogramming.

If you declare a pointer to a function like this:

int (*func)(int a, int b);

You can assign a place in memory to that function like this (requires libdl and dlopen)

#include <dlfcn.h>

int main(void)
{
    void *handle;
    char *func_name = "bla_bla_bla";
    handle = dlopen("foo.so", RTLD_LAZY);
    *(void **)(&func) = dlsym(handle, func_name);
    return func(1,2);
}

To load a local symbol using indirection, you can use dlopen on the calling binary (argv[0]).

The only requirement for this (other than dlopen(), libdl, and dlfcn.h) is knowing the arguments and type of the function.

Related