Skip to content
elohim-meth edited this page Mar 9, 2021 · 19 revisions

About

The purpose of this library is to add simple to use run-time reflection to C++ language.

Target compilers and OS

For now only GCC and Clang are supported. C++17 standard required!
Library is tested on Linux x64 (GCC and Clang) and Windows 8 (MinGW).

Rtti lib can be compiled as static or shared.
Shared is preferred way to have all type information in one place.

Usage

No preprocessor is used, so it is required to manually register the classes with its properties and methods.
Suppose we have such class:

// This header contains everything
#include <rtti/rtti.h>

namespace test {
class A
{
    // This macro declares and defines one virtual method named classInfo.
    // It's needed only if A has derived classes and you need to meta_cast
    // between them or polymorphic variant behaviour for this class hierarchy.
    DECLARE_CLASSINFO
public:
    A() {}
    explicit A(int value)
        : a(value)
    {}
    A(const A &other)
        : c(other.c), a(other.a), b(other.b)
    {}
    A(A &&other) noexcept
    {
        swap(other);
    }
    A& operator=(const A &other)
    {
        if (this != &other)
            A{other}.swap(*this);
        return *this;
    }
    A& operator=(A &&other) noexcept
    {
        if (this != &other)
            A{std::move(other)}.swap(*this);
        return *this;
    }
    void swap(A &other) noexcept
    {
        std::swap(a, other.a);
        std::swap(b, other.b);
        std::swap(c, other.c);
    }
    virtual ~A() noexcept
    {
        a = b = c = -1;
    }
    virtual void print() const noexcept
    {
        std::printf("a = %d, b = %d, c = %d \n", a, b, c);
    }
    int getA() const
    {
        return a;
    }
    void setA(int value)
    {
        a = value;
    }
    int& bValue()
    {
        return b;
    }
    const int& bValue() const
    {
        return b;
    }

    int c = -1;
private:
    int a = -1;
    int b = -1;
};
} // namespace test

Now we need to reflect this class.

void register_A()
{
    using namespace rtti;
    global_define()
        ._namespace("test")
            ._class<A>("A")
                ._constructor<int>() 
                ._method("print", &A::print)
                ._property("a", &A::getA, &A::setA)
                ._method<int& (A::*)()>("bValue", &A::bValue)
                ._method<const int& (A::*)() const>("bValue", &A::bValue)
                ._property("c", &A::c)
            ._end()
        ._end()
    ;
}

Here:

  • global_define() function returns definition object for global namespace.
  • _namespace("test") registers new meta-namespace with name "test".
    Meta-namespaces are general purpose meta-container to avoid name pollution, like ordinary C++ namespaces.
  • _class<A>("A") registers meta-class for class A with name "A".
  • _constructor<int>("name") registers constructor with one parameter of type int.
    You can specify custom name to identify this constructor or will have to use its parameter types for this purpose.
    Default, copy, and move constructors are registered automatically, if they are available, with names "default constructor", "copy constructor" and "move constructor" respectively.
    When constructor has only one parameter, it is registered as converting constructor, and can later be used to convert variant holding value of parameter type to variant of constructor class type.
  • _method("print", &A::print) registers method A::print with name "print".
    Since it's not overloaded, there is no need to specify signature.
  • _property("a", &A::getA, &A::setA) register property with name "a".
    Second and third parameters are getter and setter methods for this property.
Clone this wiki locally