📜 ⬆️ ⬇️

Mini-review of libraries 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 ++. Primarily, this information will be of interest to game developers.

Thanks to reflection, you can:
- It is easy to 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 imagination and needs.

Next comes a review of each library in turn because of my modest possibilities. For each:
- short description;
- an example of binding and use for this class:

class Test { public: int func(int a, int b) { return a + b; } }; 

- performance measurement results on i5 3570K, Windows 8, Visual Studio 2013, Release x86 (10,000,000 class method calls were measured separately and 10,000,000 metamethods + calls separately were measured).
')
Only libraries that did not require additional building steps and tools (like qt moc and gccxml) were considered.

Libraries are listed in ascending order of personal interest to them.

1) Luabind


image
github.com/rpavlik/luabind

Luabind (rpavlik's fork) is used for binding in Lua now, but you don’t use much meta information 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 under the inspiration of luabind. It looks quite cultural and worked out.
The truth has not been noticeably updated for 4 years.

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 (crash failed, took results from another library site)
- Invoke - 6889ms <- very sad

3) cpgf


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

The main author is kind of Chinese. It looks elaborated, but the interface is rather complicated and the code does not look concisely. Many prefixes, additions in 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.

From additional bells and whistles - serialization, ready-made 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, like, German. Cheers - C ++ 11. A beautiful syntax, modern features are actively developing, they are very happy. In the near future, a new version should appear with significant refactoring.

But so far, judging by the code, there is a lot of reason why the solution is quite straightforward, hence the much 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 understood 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, it was tested.

Conditional minus - to create meta-information you need to use macros, but this is due to the 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 <- not so good, but most likely and it will be optimized

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

The author himself wrote about this, comparing his decision with others. Article with graphs and pictures for the still old 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 compile time and linking time of the project and how heavy the binaries are.

Overall result
LuabindCampcpgfRTTRuMOF
Invoke1100688910001780115
FindMetaMethod + Invoke1580x113522901780


Conclusion


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

Suggestions for discussion


1) What game developers should choose a library?
cpgf solidly worked out and shows good results, but is this overhead important for invoke? May prefer, for example, more modern RTTR, because 2290ms per 10,000,000 calls is 4366812 calls per second. 72780 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 it to be used with maximum intensity (as planned). But it is not finished yet, there is a lack of 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 of or against some library.

Thanks in advance for your comments.

- UPDATE1: Comparing the performance of libraries with luabind is not entirely correct. Since calling a method in luabind means 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.

Source: https://habr.com/ru/post/257071/


All Articles