惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
云风的 BLOG
云风的 BLOG
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
D
Docker
H
Help Net Security
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Azure Blog
Microsoft Azure Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
月光博客
月光博客
C
Check Point Blog
S
SegmentFault 最新的问题
T
The Blog of Author Tim Ferriss
J
Java Code Geeks
M
MIT News - Artificial intelligence
B
Blog RSS Feed
MyScale Blog
MyScale Blog
大猫的无限游戏
大猫的无限游戏
Hugging Face - Blog
Hugging Face - Blog
腾讯CDC
美团技术团队
I
InfoQ
Blog — PlanetScale
Blog — PlanetScale

博客园 - gearslogy

PCG建筑开发 Houdini HDANC -> HDA Houdini NC HDA -> HDA PBRT 蒙特卡洛采样 BRDF是BSSRDF的一个特殊形式 来自伟大的AI UE5.7编辑器扩展 PBRT中的RayDifferentials Unreal Fur 假毛发 草地 Grass PBRT v2中,隐士表面、三角形的dpdu dpdv dndu dndv 思考 Houdini Vulkan HeightBlend 高度混合 Indexmap Vulkan矩形绘制顺序小坑 QML NextQT 随手 HDK门格海绵 clang reflection Master LLVM GEP 类型擦除TypeErase Qt问题记录 现代CPP设计模式 CPP2nd CRTP Facade 模式 billboard暴力实现 Fibonacci各种玩法 ubuntu升级编译器
C++ Runtime Reflection
gearslogy · 2024-02-02 · via 博客园 - gearslogy

参考:

1. A Flexible Reflection System in C++: Part 1 (preshing.com)

2. C++ Reflection | Austin Brunkhorst 

2做的更好。反射的代码是自动生成的。

其实还有个做法,C++ 代码里嵌个pythonVM,天生反射

python yyds:

class Base:
  def get_color(self) -> str:
    return "blue"

a = eval("Base")()
print(a.get_color())

目的

为了学习这个理念,先是从0 感受一个最简单的C++运行时反射实现:

假设:

struct Node {
    std::string key;
    int value;
}

可以实现:

int main() {
    using namespace std::string_literals;

    Node node = {"apple",3};
    auto *metaStruct = dynamic_cast<RF::MetaType_Struct*>(RF::MetaTypeResolver<Node>::get());
    metaStruct->dump(&node);
    std::cout << "after changed\n";
    metaStruct->setMember(&node, "key", "Houdini"s);
    metaStruct->setMember(&node, "value", 123);
    metaStruct->dump(&node);
    return 0;
}

运行时输出:

Node{
    key=std::string{apple}
    value=int{3}
}
after changed
Node{
    key=std::string{Houdini}
    value=int{123}
}

V0 一个结构体 2个成员:

#include <iostream>
#include <vector>
#include <any>
#include <concepts>
namespace RP_Reflection{
    struct MetaType{
        std::string typeName; // for example int, std::string
        size_t size;
        MetaType(std::string valueTypeName, size_t size) : typeName{std::move(valueTypeName)}, size{size} {}
        virtual ~MetaType() =default;
        [[nodiscard]] virtual std::string getFullTypeName() const { return typeName;}
        virtual void dump(const void *data) const= 0;
        virtual void set(void *data, std::any ) {}
    };
    // meta->string
    struct MetaType_Int: MetaType{
        explicit MetaType_Int() : MetaType{"int", sizeof(int)}{}
        void dump(const void *ptr) const override{ std::cout <<"int{" << *(static_cast<const int*>(ptr)) << "}";}
        void set(void *ptr, std::any v ) override{
            *static_cast<int*>(ptr) = std::any_cast<int>(v);
        }
    };
    // meta->int
    struct MetaType_String: MetaType{
        MetaType_String() : MetaType("std::string", sizeof(std::string)){}
        void dump(const void *ptr) const override{ std::cout <<"std::string" << "{"<< *(static_cast<const std::string*>(ptr))<< "}";}
        void set(void *ptr, std::any v ) override{
            *static_cast<std::string*>(ptr) = std::move(std::any_cast<std::string>(std::move(v)));
        }
    };
    // meta->struct
    struct MetaType_Struct: MetaType{
        struct MetaMember{
            std::string fieldName;
            size_t offset;
            MetaType *type;
        };
        std::vector<MetaMember> members;

        explicit MetaType_Struct(void (*init)(MetaType_Struct *)): MetaType{"",0} {
            init(this);
        }

        void dump(const void *ptr)const override{
            std::cout << typeName << "{"<< std::endl;
            for(const auto &member : members){
                std::cout << std::format("    {}=", member.fieldName);
                member.type->dump(static_cast<const char*>(ptr) + member.offset);
                std::cout << "\n";
            }
            std::cout << "}\n";
        }

        void setMember(void *ptr,const char *name, std::any data){
            for(auto &member : members){
                if(member.fieldName != name ) continue;
                member.type->set( static_cast<char*>(ptr) + member.offset, std::move(data));
            }
        }
    };

    // Declare the function template that handles primitive types such as int, std::string, etc.:
    template<typename T>
    MetaType *GetPrimitiveMetaType();

    // check class is MetaType
    template<typename T>
    concept isMetaType = std::is_base_of_v<MetaType, std::remove_cvref_t<std::remove_pointer_t<T>> >;

    // check a class that was reflected
    template<typename T>
    concept isReflectedClass = requires(T){
        { T::reflection } -> isMetaType;
    };

    // TemplateMethod Get MetaType
    template<typename T>
    struct MetaTypeResolver{
        static MetaType *get(){
            if constexpr (isReflectedClass<T>)
                return &T::reflection;
            else return GetPrimitiveMetaType<T>();
        }
    };

    template<>
    MetaType *GetPrimitiveMetaType<int>(){
        static MetaType_Int metaInt;
        return &metaInt;
    }
    template<>
    MetaType *GetPrimitiveMetaType<std::string>(){
        static MetaType_String metaStr;
        return &metaStr;
    }

} // end of namespace


namespace RF = RP_Reflection;

struct Node {
    std::string key;
    int value;

    // REFLECTION CODE HERE
    static RF::MetaType_Struct reflection;
    static void initReflection(RF::MetaType_Struct *);
};

RF::MetaType_Struct Node::reflection(Node::initReflection);

void Node::initReflection(RF::MetaType_Struct *ms) {
    ms->typeName = "Node";
    ms->size = sizeof(Node);
    ms->members = {
            {"key", offsetof(Node, key), RF::MetaTypeResolver<decltype(Node::key)>::get()},
            {"value", offsetof(Node, value), RF::MetaTypeResolver<decltype(Node::value)>::get()},
    };
}

int main() {
    using namespace std::string_literals;

    Node node = {"apple",3};
    auto *metaStruct = dynamic_cast<RF::MetaType_Struct*>(RF::MetaTypeResolver<Node>::get());
    metaStruct->dump(&node);
    std::cout << "after changed\n";
    metaStruct->setMember(&node, "key", "Houdini"s);
    metaStruct->setMember(&node, "value", 123);
    metaStruct->dump(&node);
    return 0;
}

 输出:

Node{
    key=std::string{apple}
    value=int{3}
}
after changed
Node{
    key=std::string{Houdini}
    value=int{123}
}

 V1 Json Dump 和std::vector<Node>

#include <iostream>
#include <vector>
#include <any>
#include <concepts>
#include <functional>
#include <ranges>
#include "json.hpp"

namespace RP_Reflection{
    struct MetaType{
        std::string typeName; // for example int, std::string
        size_t size;
        MetaType(std::string valueTypeName, size_t size) : typeName{std::move(valueTypeName)}, size{size} {}
        virtual ~MetaType() =default;
        [[nodiscard]] virtual std::string getFullTypeName() const { return typeName;}
        virtual void dump(const void *data, nlohmann::json &io) const= 0;
        virtual void set(void *data, std::any ) {}
    };
    // meta->string
    struct MetaType_Int: MetaType{
        explicit MetaType_Int() : MetaType{"int", sizeof(int)}{}
        void dump(const void *ptr, nlohmann::json &io) const override{
            io["type"] = typeName;
            io["value"] =  *(static_cast<const int*>(ptr));
        }
        void set(void *ptr, std::any v ) override{
            *static_cast<int*>(ptr) = std::any_cast<int>(v);
        }
    };
    // meta->int
    struct MetaType_String: MetaType{
        MetaType_String() : MetaType("std::string", sizeof(std::string)){}
        void dump(const void *ptr,nlohmann::json &io) const override{
            io["type"] = typeName;
            io["value"] =  *(static_cast<const std::string *>(ptr));
        }
        void set(void *ptr, std::any v ) override{
            *static_cast<std::string*>(ptr) = std::move(std::any_cast<std::string>(std::move(v)));
        }
    };
    // meta->struct
    struct MetaType_Struct: MetaType{
        struct MetaMember{
            std::string fieldName;
            size_t offset;
            MetaType *type;
        };
        std::vector<MetaMember> members;

        explicit MetaType_Struct(void (*init)(MetaType_Struct *)): MetaType{"",0} {
            init(this);
        }

        void dump(const void *ptr,nlohmann::json & io)const override{
            io["type"] = typeName;
            io["value"] ={};
            for(const auto &member : members){
                nlohmann::json tempIO;
                tempIO["member_name"] = member.fieldName;
                member.type->dump(static_cast<const char*>(ptr) + member.offset, tempIO);
                io["value"].emplace_back(tempIO);
            }

        }


        void setMember(void *ptr,const char *name, std::any data){
            for(auto &member : members){
                if(member.fieldName != name ) continue;
                member.type->set( static_cast<char*>(ptr) + member.offset, std::move(data));
            }
        }
    };

    // Declare the function template that handles primitive types such as int, std::string, etc.:
    template<typename T>
    MetaType *GetPrimitiveMetaType();

    // check class is MetaType
    template<typename T>
    concept isMetaType = std::is_base_of_v<MetaType, std::remove_cvref_t<std::remove_pointer_t<T>> >;

    // check a class that was reflected
    template<typename T>
    concept isReflectedClass = requires(T){
        { T::reflection } -> isMetaType;
    };

    // TemplateMethod Get MetaType
    template<typename T>
    struct MetaTypeResolver{
        static MetaType *get(){
            if constexpr (isReflectedClass<T>)
                return &T::reflection;
            else return GetPrimitiveMetaType<T>();
        }
    };

    template<>
    MetaType *GetPrimitiveMetaType<int>(){
        static MetaType_Int metaInt;
        return &metaInt;
    }
    template<>
    MetaType *GetPrimitiveMetaType<std::string>(){
        static MetaType_String metaStr;
        return &metaStr;
    }


    struct MetaType_StdVector: MetaType{
        MetaType *elementMetaType; // init in ctor
        // three function set value
        size_t (*getSize) (const void *vecPtr);
        const void* (*getItem)(const void *vecPtr, size_t idx);
        void (*setItem)(void *vecPtr, size_t idx, std::any v);
        void (*anyCasting)(void *vecPtr, std::any v);

        //
        template<typename ItemType>
        explicit MetaType_StdVector(ItemType *) : MetaType("std::vector<>", sizeof(std::vector<ItemType>)),elementMetaType(MetaTypeResolver<ItemType>::get()) {
            using vec_t = std::vector<ItemType>;
            getSize = [](const void *vecPtr){
                const auto& vec = *static_cast<const vec_t*>(vecPtr);
                return vec.size();
            };
            getItem = [](const void *vecPtr, size_t idx){
                const auto& vec = *static_cast<const vec_t*>(vecPtr);
                return static_cast<const void*>(&vec[idx]);
            };
            setItem = [](void *vecPtr, size_t idx, std::any v){
                auto elem_v = std::any_cast<ItemType>(v);
                (*static_cast<vec_t *>(vecPtr) ) [idx] = elem_v;
            };
            anyCasting = [](void *vecPtr, std::any v){
                auto vec = std::any_cast<vec_t>(std::move(v) );
                *static_cast<vec_t*>(vecPtr) = std::move(vec);
            };

        }
        [[nodiscard]] std::string getFullTypeName() const override{
            return std::string("std::vector<") + elementMetaType->getFullTypeName() + ">";
        }

        void dump(const void *obj,nlohmann::json &io) const override{
            io["type"] = getFullTypeName();
            io["value"] ={};
            for(int i=0;i<getSize(obj);i++){
                nlohmann::json tempIO;
                elementMetaType->dump(getItem(obj, i), tempIO);
                io["value"].emplace_back(tempIO);
            }

        }
        void set(void *ptr, std::any v) override{
            anyCasting(ptr,v);
        }

    };

    template<typename T>
    struct MetaTypeResolver<std::vector<T>>{
        static MetaType *get(){
            static MetaType_StdVector typeDesc{(T*) nullptr};
            return &typeDesc;
        }
    };



} // end of namespace


namespace RF = RP_Reflection;

struct Node {
    std::string key;
    int value;
    std::vector<Node> children;
    // REFLECTION CODE HERE
    static RF::MetaType_Struct reflection;
    static void initReflection(RF::MetaType_Struct *);
};

RF::MetaType_Struct Node::reflection(Node::initReflection);

void Node::initReflection(RF::MetaType_Struct *ms) {
    ms->typeName = "Node";
    ms->size = sizeof(Node);
    ms->members = {
            {"key", offsetof(Node, key), RF::MetaTypeResolver<decltype(Node::key)>::get()},
            {"value", offsetof(Node, value), RF::MetaTypeResolver<decltype(Node::value)>::get()},
            {"children", offsetof(Node, children), RF::MetaTypeResolver<decltype(Node::children)>::get()},
    };
}


int main() {
    using namespace std::string_literals;
    Node subNode1 = {"jog", 123,{}};
    Node subNode2 = {"sprint", 1500,{}};

    Node node = {"apple",3,
                 { std::move(subNode1), std::move(subNode2)}   };
    auto *metaStruct = dynamic_cast<RF::MetaType_Struct*>(RF::MetaTypeResolver<Node>::get());

    // dump
    nlohmann::json j;
    metaStruct->dump(&node, j);
    std::cout << j.dump(4) << std::endl;

    // change and dump
    std::cout << "----after changed----\n";
    metaStruct->setMember(&node, "key", "Houdini"s);
    metaStruct->setMember(&node, "value", 123);
    metaStruct->dump(&node, j);
    std::cout << j.dump(4) << std::endl;
    return 0;
}