C++RTTR反射库使用

介绍

RTTR代表运行时类型反射。它描述了计算机程序在运行时查询和修改对象的能力。这也是库本身的名称,它是用C++编写的,并作为开源库发布。您可以在以下网址找到更多信息:www.rttr.org

安装

github上下载rttr代码包,将其解压缩后运行CMake。将src下的rttr文件夹和编译完成的库一起拷走。

运行样例以确定配置成功:

#include<rttr/registration>
#include<iostream>
using namespace rttr;
using namespace std;
class MyStruct 
{
public:
    MyStruct(){}; 
    void func(double){}; 
    int data; 
RTTR_ENABLE()
};
RTTR_REGISTRATION
{
    registration::class_<MyStruct>("MyStruct")
        .constructor<>()
        .property("data",&MyStruct::data)
        .method("func",&MyStruct::func);
}
int main(int argc, char const *argv[])
{
    type t=type::get<MyStruct>();
    for(auto &prop:t.get_properties())
        cout<<"name: "<<prop.get_name()<<endl;
    for(auto &meth:t.get_methods())
        cout<<"name: "<<meth.get_name()<<endl;
    return 0;
}

输出应为:

name: data
name: func

正式开始!

注册

在RTTR中,所有反射的标识都应手动注册。正式的注册应以

RTTR_REGISTRATION
{

为开始。
例如,以下代码注册了一个名为func的函数,一个名为aaa的变量和一个名为A的枚举:

RTTR_REGISTRATION
{
    registration::method("func",func);
    registration::property("aaa",aaa);
    registration::enumeration<A>("A")
    (
        value("a",A::a),
        value("b",A::b),
        value("c",A::c)
    );
}

对于多个函数的重载,应使用static_cast指定。
如,指定参数为int,long long,string的重载函数:

static_cast<void(Active::*)(int,long long,string)>(&Active::try_one)

注册类也很简单。使用registration::class_可以注册一个类。
如:

RTTR_REGISTRATION
{
    registration::class_<MyStruct>("MyStruct")
        .constructor<>()
        .property("data",&MyStruct::data)
        .method("func",&MyStruct::func);
}

注册的类必须包含RTTR_ENABLE()。或者如果需要访问私有属性,请导入rttr/registration_friend并将RTTR_REGISTRATION_FRIEND加入类中。

我们还可以使用registration::property_readonly注册一个只读属性!只读属性无法通过反射进行修改。

添加 access_levels可以指定此属性的访问等级,有三个等级可选:

  • access_levels::public_access
  • access_levels::private_access
  • access_levels::protected_access

type类

我们可以使用type类访问已经注册过的信息。
例如,获取一个支持rttr反射的类的type:

Active a;
...
type ty=a.get_type();

type对象会描述一个特定对象的属性。可能最常用的type方法就是get_name。这个方法将返回对象的名字。例如,下面这条语句:

cout<<a.get_type().get_name();

则会输出:

Active

还可以使用静态方法get_by_name获取相应的对象:

const char *name="Active";
type ty=type::get_by_name(name);

可以使用is_valid方法判断此对象是否存在。

也可以使用另一种方式获得type对象:

type ty1=type::get<Active>();
type ty2=type::get<int>();
type ty3=type::get<double*>();

可以使用==运算符比较两个type对象。例如:

if(a.get_type()==type::get<Active>()) ...

可以使用type类构造类的实例。调用get_constructor方法将得到一个constructor类型的对象,然后使用invoke方法来构造一个实例。例如:

const char *name="Active";

type ty=type::get_by_name(name);
variant v=ty.get_constructor().invoke();

调用v.get_value<Active>可以得到这个值。
如果这个类没有无参数的构造器,则get_constructor方法不会有任何作用。

使用rttr分析类

rttr命名空间下有三个类property,method 和 constructor,分别用于描述变量,方法和构造器。这三个类都有一个名为 get_name 的方法,用来返回变量,方法或构造器的名字。property 类有一个 get_type 方法,用来返回描述变量类型的一个对象,这个对象的类型同样是 type。method 和 constructor 类有报告参数类型的方法,method类还有一个报告返回类型的方法。
type类中的get_propertiesget_methodsget_constructors方法将分别返回这个类中声明的字段,方法和构造器的列表(不可变),但不包括父类的成员。
下面的程序显示了如何打印一个类的全部信息。你可能需要花费较长的时间来注册这个类。

#include<rttr/registration>
#include<iostream>
using namespace rttr;
using namespace std;
RTTR_REGISTRATION
{
    registration::class_<method>("method")
        .method("is_valid",&method::is_valid)
        .method("operator bool",&method::operator bool)
        .method("get_name",&method::get_name)
        .method("get_access_level",&method::get_access_level)
        .method("is_static",&method::is_static)
        .method("get_return_type",&method::get_return_type)
        .method("get_declaring_type",&method::get_declaring_type)
        .method("get_parameter_infos",&method::get_parameter_infos)
        .method("get_signature",&method::get_signature)
        .method("get_metadata",&method::get_metadata)
        .method("invoke",static_cast<variant(method::*)(instance) const>(&method::invoke))
        .method("invoke",static_cast<variant(method::*)(instance,argument) const>(&method::invoke))
        .method("invoke",static_cast<variant(method::*)(instance,argument,argument) const>(&method::invoke))
        .method("invoke",static_cast<variant(method::*)(instance,argument,argument,argument) const>(&method::invoke))
        .method("invoke",static_cast<variant(method::*)(instance,argument,argument,argument,argument) const>(&method::invoke))
        .method("invoke",static_cast<variant(method::*)(instance,argument,argument,argument,argument,argument) const>(&method::invoke))
        .method("invoke",static_cast<variant(method::*)(instance,argument,argument,argument,argument,argument,argument) const>(&method::invoke))
        .method("invoke_variadic",&method::invoke_variadic)
        .method("operator==",&method::operator==)
        .method("operator!=",&method::operator!=);
}
void print_base(type ty)
{
    auto l=ty.get_base_classes();
    int j=0;
    for(auto i=l.begin();i!=l.end();++i,j++)  // base classes应在RTTR_ENABLE宏中指定
    {
        cout<<": ";
        cout<<i->get_name();
    }
    cout<<endl;
}
void print_methods(type ty)
{
    for(auto i:ty.get_methods())
    {
        cout<<"    ";
        if(i.is_static())
            cout<<"static ";
        cout<<i.get_return_type().get_name();
        cout<<' '<<i.get_name();
        cout<<'(';
        if(i.get_parameter_infos().size()!=0)
        {
            int k=0;
            for(auto j:i.get_parameter_infos())
            {
                if(k!=0)
                    cout<<',';
                cout<<j.get_type().get_name();
                k+=1;
            }
        }
        cout<<");"<<endl;
    }
}
void print_prop(type ty)
{
    for(auto i:ty.get_properties())
    {
        cout<<"    ";
        if(i.is_static())
            cout<<"static ";
        if(i.is_readonly())
            cout<<"const ";
        cout<<i.get_type().get_name();
        cout<<' '<<i.get_name();
        cout<<endl;
    }
}
void print_constructors(type ty)
{
    for(auto i:ty.get_constructors())
    {
        cout<<"    ";
        cout<<i.get_signature();
        cout<<' ';
        cout<<i.get_declaring_type().get_name();
        cout<<" (";
        int k=0;
        for(auto j:i.get_parameter_infos())
        {
            if(k!=0)
                cout<<", ";
            cout<<j.get_type().get_name();
        }
        cout<<");"<<endl;
    }
}
int main(int argc, char const *argv[])
{
    type ty=type::get<method>();
    cout<<"class "<<ty.get_name();
    print_base(ty);
    cout<<"{"<<endl;
    cout<<"public:"<<endl;
    print_methods(ty);
    print_prop(ty);
    print_constructors(ty);
    cout<<"}";
    return 0;
}

它将会输出:

class method
{
public:
    bool is_valid();
    bool operator bool();
    rttr::basic_string_view<char,std::char_traits<char>> get_name();
    rttr::access_levels get_access_level();
    bool is_static();
    rttr::type get_return_type();
    rttr::type get_declaring_type();
    rttr::array_range<rttr::parameter_info,rttr::detail::default_predicate<rttr::parameter_info>> get_parameter_infos();
    rttr::basic_string_view<char,std::char_traits<char>> get_signature();
    rttr::variant get_metadata(rttr::variant);
    rttr::variant invoke(rttr::instance);
    rttr::variant invoke(rttr::instance,rttr::argument);
    rttr::variant invoke(rttr::instance,rttr::argument,rttr::argument);
    rttr::variant invoke(rttr::instance,rttr::argument,rttr::argument,rttr::argument);
    rttr::variant invoke(rttr::instance,rttr::argument,rttr::argument,rttr::argument,rttr::argument);    rttr::variant invoke(rttr::instance,rttr::argument,rttr::argument,rttr::argument,rttr::argument,rttr::argument);
    rttr::variant invoke(rttr::instance,rttr::argument,rttr::argument,rttr::argument,rttr::argument,rttr::argument,rttr::argument);
    rttr::variant invoke_variadic(rttr::instance,std::vector<rttr::argument,std::allocator<rttr::argument>>);
    bool operator==(method);
    bool operator!=(method);
}

使用constructor创建类的实例

在rttr中,可以方便的使用constructor类生成一个类的实例。
我们需要先获得一个构造器:

auto con=ty.get_constructor({type::get<int>()});

表示获取一个参数为int的构造器。
接着我们需要构造它:

variant v=con.invoke(10);

调用invoke时,最多只能有六个参数。
variant类 类似any,表示可以存储任意类型的变量。

最后,我们需要获得构造完成的实例:

Active a=v.get_value<Active>();

使用method类运行函数

在rttr中提供了一个method类,可以方便的让我们运行一个函数。
运行函数的方法如下:

func.invoke(var,...)

如果func是一个静态函数,那么应为 {}
否则var为这个类的实例。
后面的参数表示这个函数的参数,超过六个的参数应该用 {} 包裹。

下面的代码演示了如何使用method类调用sqrt和log:

#include<rttr/registration>
#include<iostream>
#include<cmath>
using namespace rttr;
using namespace std;
RTTR_REGISTRATION
{
    registration::method("sqrt",static_cast<long double(*)(long double)>(sqrt));
    registration::method("log2",static_cast<long double(*)(long double)>(log2));
    registration::method("log",static_cast<long double(*)(long double)>(log));
    registration::method("log10",static_cast<long double(*)(long double)>(log10));
}
int main(int argc, char const *argv[])
{
    string op;
    long double n;
    while(cin>>op)
    {
        cin>>n;
        method m=type::get_global_method(op);
        if(!m)
        {
            cout<<"Undefined"<<endl;
            continue;
        }
        cout<<m.invoke({},n).get_value<long double>()<<endl;
    }
    return 0;
}

参考:

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用反射技术来获取类成员中的属性并以字符串方式输出。反射是一种在运行时检查、访问和修改程序元素的能力。在C++11中,可以使用一些来实现反射,例如Boost.Reflection和RTTR(Run Time Type Reflection)。 以下是一个使用Boost.Reflection的示例代码,可以获取类成员中的属性并以字符串方式输出: ```c++ #include <iostream> #include <boost/reflection.hpp> class MyClass { public: MyClass(int id, const std::string& name) : id_(id), name_(name) {} int get_id() const { return id_; } const std::string& get_name() const { return name_; } private: int id_; std::string name_; }; int main() { MyClass obj(1, "Alice"); boost::reflection::Object obj_ref(obj); boost::reflection::Type obj_type = obj_ref.GetType(); std::vector<boost::reflection::Property> properties = obj_type.GetProperties(); for (const auto& property : properties) { std::cout << property.GetName() << ": " << property.GetValue(obj_ref) << std::endl; } return 0; } ``` 在上面的示例代码中,我们定义了一个名为MyClass的类,并在其中定义了成员变量id_和name_,以及成员函数get_id()和get_name()。接下来,在main函数中,我们创建了一个MyClass对象,并使用boost::reflection::Object类来获取对象的引用。然后,我们使用boost::reflection::Type类来获取对象的类型,并使用GetProperties()函数获取对象的所有属性。最后,我们使用属性的名称和GetValue()函数来输出属性的值。 需要注意的是,Boost.Reflection是一个第三方,需要在项目中添加相应的头文件和链接。如果不想使用第三方,也可以手动实现反射功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值