C++类反射

#include <any>
#include <cstddef>
#include <sstream>
#include <string>
#include <tuple>
#include <vector>
#include <iostream>

// https://www.rttr.org/download
// https://blog.csdn.net/qq_30220519/article/details/139268669
// https://github.com/skypjack/meta
namespace reflect {

    struct member_info {
        const char* name;
        std::size_t offset;
        std::size_t size;
        std::size_t align;
        std::type_info const& type;
    };

    template <class Class, class Member>
    struct typed_member_info : member_info {
        Member Class::* access;

        using member_type = Member;

        template <class T>
        static constexpr std::is_same<T, member_type> is() {
            return {};
        }
    };

    struct class_meta_info {
        const char* name;
        std::size_t size;
        std::size_t align;
        std::type_info const& type;
    };

    template <class Class, class ...Members>
    struct reflect_info {
        using class_type = Class;

        class_meta_info meta;
        std::tuple<Members...> members;

        template <class F>
        constexpr void for_each_member(F&& f) const {
            std::apply([&](auto &&...args) {
                (f(args), ...);
                }, members);
        }
    };

    template <class Class, class ...Members>
    constexpr reflect_info<Class, Members...> make_reflect_info(class_meta_info meta, Members ...members) {
        return { meta, std::make_tuple(members...) };
    }

    template <class T>
    struct reflect_traits {
        [[deprecated("reflect trait not declared on this type")]] static constexpr struct {
        } info{};
    };

#define REFLECT_CLASS_BEGIN(Type, ...) \
template <__VA_ARGS__> \
struct reflect::reflect_traits<Type> { \
    using class_type = Type; \
    static constexpr auto info = make_reflect_info<class_type>( \
        class_meta_info{ \
                #Type, \
                sizeof(class_type), \
                alignof(class_type), \
                typeid(class_type), \
            }
#define REFLECT_CLASS(member) \
        , typed_member_info<class_type, decltype(class_type::member)>{ \
            { \
                #member, \
                offsetof(class_type, member), \
                sizeof(decltype(class_type::member)), \
                alignof(decltype(class_type::member)), \
                typeid(decltype(class_type::member)), \
            }, \
            &class_type::member, \
        }
#define REFLECT_CLASS_END() \
    ); \
};

    template <class T, class F>
    constexpr void for_each_member(T& object, F&& f) {
        using trait_type = reflect_traits<std::remove_const_t<T>>;
        trait_type::info.for_each_member([&](auto const& member) {
            f(member.name, object.*(member.access));
            });
    }

    template <class T, class F>
    constexpr void for_each_member(F&& f) {
        using trait_type = reflect_traits<std::remove_const_t<T>>;
        trait_type::info.for_each_member(f);
    }

    template <class Member, class T>
    constexpr std::conditional_t<std::is_const_v<T>, Member const, Member>& get_member(T& object, std::string const& name) {
        using trait_type = reflect_traits<std::remove_const_t<T>>;
        std::conditional_t<std::is_const_v<T>, Member const, Member>* member_p = nullptr;
        trait_type::info.for_each_member([&](auto const& member) {
            if (member_p) return;
            if (member.name == name) {
                if constexpr (member.template is<Member>()) {
                    member_p = std::addressof(object.*(member.access));
                }
                else {
                    throw std::logic_error("member `" + name + "` has type `" + member.type.name() + "`, given type is `" + typeid(Member).name() + "`");
                }
            }
            });
        if (!member_p)
            throw std::logic_error("no such member named `" + name + "`");
        return *member_p;
    }

    template <class Any = std::any, class T>
    constexpr Any get_member_any(T& object, std::string const& name) {
        using trait_type = reflect_traits<std::remove_const_t<T>>;
        Any member_any;
        trait_type::info.for_each_member([&](auto const& member) {
            if (member_any.has_value()) return;
            if (member.name == name) {
                member_any = object.*(member.access);
            }
            });
        return member_any;
    }

    template <class T, class Member = void>
    constexpr bool has_member(std::string const& name) {
        using trait_type = reflect_traits<std::remove_const_t<T>>;
        enum Status {
            NotFound = 0,
            Found,
            TypeMismatch,
        } status = NotFound;
        trait_type::info.for_each_member([&](auto member) {
            if (status != NotFound) return;
            if (member.name == name) {
                if constexpr (member.template is<Member>()) {
                    status = Found;
                }
                else {
                    status = TypeMismatch;
                }
            }
            });
        if constexpr (std::is_void_v<Member>) {
            return status != NotFound;
        }
        else {
            return status == Found;
        }
    }

    template <class T>
    constexpr std::type_info const& get_member_type(std::string const& name) {
        using trait_type = reflect_traits<std::remove_const_t<T>>;
        std::type_info const* member_type = nullptr;
        trait_type::info.for_each_member([&](auto const& member) {
            if (member_type) return;
            if (member.name == name) {
                member_type = member.type;
            }
            });
        if (!member_type)
            throw std::logic_error("no such member named `" + name + "`");
        return *member_type;
    }

    template <class T, class Member>
    constexpr bool member_type_is(std::string const& name) {
        using trait_type = reflect_traits<std::remove_const_t<T>>;
        enum Status {
            NotFound = 0,
            Found,
            TypeMismatch,
        } status = NotFound;
        trait_type::info.for_each_member([&](auto member) {
            if (status != NotFound) return;
            if (member.name == name) {
                if constexpr (member.template is<Member>()) {
                    status = Found;
                }
                else {
                    status = TypeMismatch;
                }
            }
            });
        if (status == NotFound)
            throw std::logic_error("no such member named `" + name + "`");
        return status == Found;
    }

    template <class T>
    constexpr member_info get_member_info(std::string const& name) {
        using trait_type = reflect_traits<std::remove_const_t<T>>;
        member_info const* member_info = nullptr;
        trait_type::info.for_each_member([&](auto const& member) {
            if (member_info) return;
            if (member.name == name) {
                member_info = &member;
            }
            });
        if (!member_info)
            throw std::logic_error("no such member named `" + name + "`");
        return *member_info;
    }

    template <class T>
    constexpr class_meta_info get_class_info() {
        using trait_type = reflect_traits<std::remove_const_t<T>>;
        return trait_type::info.meta;
    }

    template <class T>
    constexpr std::vector<std::string> get_member_names() {
        using trait_type = reflect_traits<std::remove_const_t<T>>;
        std::vector<std::string> member_names;
        trait_type::info.for_each_member([&](auto const& member) {
            member_names.push_back(member.name);
            });
        return member_names;
    }

    template <class T>
    constexpr std::vector<member_info> get_member_infos() {
        using trait_type = reflect_traits<std::remove_const_t<T>>;
        std::vector<member_info> members;
        trait_type::info.for_each_member([&](auto const& member) {
            members.push_back(member);
            });
        return members;
    }

    template <class T>
    std::ostream& print(std::ostream& os, T const& object) {
        bool once = false;
        for_each_member(object, [&](const char* name, auto& member) {
            if (once) {
                os << ", ";
            }
            else {
                once = true;
            }
            os << name;
            os << ": ";
            print(member);
            });
        os << "}";
        return os;
    }

}

// ===== TEST ZONE =====

using namespace reflect;

struct Student {
    std::string name;
    int age;
};

REFLECT_CLASS_BEGIN(Student)
REFLECT_CLASS(name)
REFLECT_CLASS(age)
REFLECT_CLASS_END();


int test() {
    Student stu{ "彭于斌", 23 };
    for_each_member(stu, [&](const char* name, auto& member) {
        std::cout << name << ": " << member << '\n';
        });
    for_each_member(stu, [&](const char* name, auto& member) {
        if constexpr (std::is_same_v<std::decay_t<decltype(member)>, int>) {
            member = 10;
        }
        else if constexpr (std::is_same_v<std::decay_t<decltype(member)>, std::string>) {
            member = "mq白律师";
        }
        });
    get_member<std::string>(stu, "name") = "mq白律师";
    for_each_member<Student>([&](auto member) {
        std::cout << member.name << ": " << member.offset << '\n';
        });
    get_member_names<Student>();
    get_member_infos<Student>();
    has_member<Student>("age");
    has_member<Student, short>("age");
    member_type_is<Student, const char*>("name");

    //std::string str = serialize(student);
    //Student student2 = deserialize(str);
    return 0;
}

输出

name: 彭于斌
age: 23
name: 0
age: 40
test ~ctor 

Download |RTTR

C++ enum 和 string互转_c++ string 转 enum-CSDN博客

GitHub - skypjack/meta: Header-only, non-intrusive and macro-free runtime reflection system in C++


创作不易,小小的支持一下吧!

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码力码力我爱你

创作不易,小小的支持一下吧!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值