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

推荐订阅源

钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
美团技术团队
Last Week in AI
Last Week in AI
WordPress大学
WordPress大学
博客园 - 三生石上(FineUI控件)
博客园 - 聂微东
雷峰网
雷峰网
阮一峰的网络日志
阮一峰的网络日志
博客园 - 叶小钗
IT之家
IT之家
Google DeepMind News
Google DeepMind News
D
Docker
J
Java Code Geeks
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 【当耐特】
V
V2EX
Hugging Face - Blog
Hugging Face - Blog
博客园 - Franky
月光博客
月光博客
宝玉的分享
宝玉的分享
酷 壳 – CoolShell
酷 壳 – CoolShell
aimingoo的专栏
aimingoo的专栏
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

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