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

推荐订阅源

美团技术团队
B
Blog RSS Feed
博客园_首页
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Google DeepMind News
Google DeepMind News
D
Docker
Blog — PlanetScale
Blog — PlanetScale
M
MIT News - Artificial intelligence
C
Check Point Blog
The Cloudflare Blog
T
Tailwind CSS Blog
大猫的无限游戏
大猫的无限游戏
量子位
The GitHub Blog
The GitHub Blog
Microsoft Azure Blog
Microsoft Azure Blog
I
InfoQ
T
The Blog of Author Tim Ferriss
博客园 - 【当耐特】
Vercel News
Vercel News
P
Proofpoint News Feed
Hugging Face - Blog
Hugging Face - Blog
V
V2EX
博客园 - 司徒正美

博客园 - 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;
}