Mini library overview for Reflection in C ++

Due to the modest information on this topic, in this article I will conduct a small review and comparison of the found libraries for Reflection in C ++. First of all, this information will be of interest to game developers.

Thanks to reflection, you can:
- Easily create editors, including interfaces, as there is convenient access to meta-information about all the properties of your objects;
- Add binding for many scripting languages ​​at once (Lua, Python, JavaScript, etc.);
- Use meta-information for automatic serialization;
- Use as a factory of objects, creating the necessary instances, having only a string with the name type;
- Use as a more lightweight replacement dynamic_cast;
- And so on and so forth, depending on the imagination and needs.

Next is an overview of each library in turn due to my modest capabilities. For each:
- a short description;
- an example of binding and usage for such a class:

classTest
{public:
  intfunc(int a, int b){
    return a + b;
  }
};

- results of measuring performance on i5 3570K, Windows 8, Visual Studio 2013, Release x86 (separately measured 10,000,000 class method calls and 10,000,000 metamethod search + call separately).

Only libraries that did not require additional construction steps and tools (like qt moc and gccxml) were considered.

Libraries are listed in increasing order of personal interest in them.

1) Luabind


image
github.com/rpavlik/luabind

Now for binding in Lua, Luabind (rpavlik's fork) is used, but the resulting meta information is not used for anything else.

Example
luabind::module(state)
[
  luabind::class_<Test>("Test")
    .def("func", &Test::func)
];


local obj = Test()
obj:func(1, 2)


Benchmark
- Invoke - 1100ms
- FindMetaMethod + Invoke - 1580ms

2) Camp


image
projects.tegesoft.com/pm/projects/camp
github.com/tegesoft/camp

Created by a French company inspired by luabind. It looks quite culturally and worked out.
The truth does not significantly updated for the year 4.

Example
CAMP_TYPE(Test)
camp::Class::declare<Test>("Test")
  .function("func", &Test::func);
Test obj;
camp::Class t = camp::classByName("Test");
camp::Function m = t->function("func");
camp::Value v = m->call(obj, camp::Args(1, 2));
auto result = v.to<int>()


Benchmark (failed to build, took the results from the site of another library)
- Invoke - 6889ms <- very sad

3) cpgf


image
www.cpgf.org/document/index.html
github.com/cpgf/cpgf

The main author is like a Chinese. It looks worked out, but the interface is quite complicated and the code does not look concise at all. Many prefixes, additions to naming, various interfaces, rules of use (for example, how and when ownership is transferred). A simple example is not visible, but if you look at the tutorial, it becomes very noticeable - github.com/cpgf/cpgf/blob/develop/samples/tutorials/a01_reflect_to_global.cpp
At the same time, everything is reduced to a single interface, which of course pleases.

A big plus is good documentation.

Of the additional bells and whistles - serialization, turnkey solutions for binding in Lua / JavaScript / Python, tweening, its own event system.

The bug fixes were back in December, that is, the project is not dead.

Example
cpgf::GDefineMetaClass<Test>
  ::define("Test")
  ._method("func", &CpgfTest::func);
Test obj;
cpgf::GMetaClass* t = cpgf::findMetaClass("Test");
cpgf::GMetaMethod* m = t->getMethod("func");
cpgf::GVariant v = m->invoke(&obj, 1, 2);
auto result = cpgf::fromVariant<int>(v);


Benchmark
- Invoke - 1000ms
- FindMetaMethod + Invoke - 1135ms <- faster than luabind

4) RTTR


image
www.axelmenzel.de/projects/coding/rttr

The author, it seems, is a German. Hooray - C ++ 11. Actively developed, beautiful syntax, modern features, very happy. In the near future, a new version should appear with significant refactoring.

But for now, judging by the code, there is a lot of straightforward solution for which, hence the significantly worse performance indicators.

Example
RTTR_DECLARE_STANDARD_TYPE_VARIANTS(Test);
RTTR_REGISTER
{
  rttr::class_<Test>()
    .method("func", &Test::func);
}
Test obj;
rttr::type t = type::get("Test");
rttr::method m = t.get_method("func");
rttr::variant v = m.invoke_variadic(obj, {1, 2});
auto result = v.get_value<int>();


Benchmark
- Invoke - 1780ms
- FindMetaMethod + Invoke - 2290ms

5) uMOF


image
bitbucket.org/occash/umof

Russian- speaking author, actively answers all questions. It was created, as I understand it, under the great impression of QT. Hurray again - C ++ 11 (all these constexpr and other joys). Actively developing. In the near future, a new version should appear with significant refactoring and acceleration, and it was tested.

Conditional minus - you need to use macros to create meta-information, but this is due to implementation features (explained later).

Example
U_DECLARE_API(Test, METHODS);
U_DECLARE_METHODS(Test)
{
  U_METHOD(func)
};
const Api* api = U_API(Test)::api();
Method m = api->method(api->indexOfMethod("func(int,int)"));
int result;
m.invoke(&obj, result, {1, 2}));


Benchmark
- Invoke - 115ms <- magic (in the old version 420, which is also a
cut above the others) - FindMetaMethod + Invoke - 1780ms <- is not so good, but most likely this will be optimized by

Invoke almost 9 times faster than the best result other libraries.

The author himself wrote about this, comparing his decision with others. To get graphics and pictures for an older version here - www.gamedev.net/page/resources/_/technical/general-programming/implementing-a-meta-system-in-c-r3905
There is also a comparison of how which libraries affect the compilation and linking times of the project and how much the binary is heavier.

Overall result
LuabindCampcpgfRTTRuMOF
Invoke1100688910001780115
FindMetaMethod + Invoke1580x113522901780


Conclusion


The most modern, concise and lively libraries - uMOF, RTTR.
The richest in functionality is cpgf.
Outstanding in performance:
- uMOF (due to implementation features, incredibly fast invoke and minimal overhead in compilation and binary size);
- cpgf (currently the fastest result for FindMetaMethod + Invoke, which is the most common use case).

Suggestions for discussion


1) What kind of game developer should I choose a library?
cpgf is solidly designed and shows good results, but is this overhead important for invoke? May give preference, for example, to a more modern RTTR, as 2290ms per 10,000,000 calls is 4,366,812 calls per second. 72,780 calls per frame at 60 FPS. That is, if about 700 calls are made on each frame, then at 60 FPS this will be less than 1% of the frame time.
At the same time, uMOF shows outstanding results, which would allow using it with maximum intensity (which is planned). But it is not finished yet, it lacks some functionality.
2) Maybe some library is missing? You could add it to the review.
3) What do you know from your experience about any of these libraries? Here the review was superficial, maybe your experience speaks of some significant features in favor or against some library.

Thanks in advance for your comments.

- UPDATE1: Comparing library performance with luabind is not entirely correct. Because calling a method in luabind involves not only finding a meta method, but also working with the lua virtual machine. I will try to update the article as soon as there is more useful information on this topic.

Also popular now: