“Poor Man's Reflection” (AKA bottom-up reflection) in C++

后端 未结 3 1717
隐瞒了意图╮
隐瞒了意图╮ 2020-12-19 15:01

I am implementing some rudimentary reflection in C++ for an ultra modular architecture where virtually all features are loaded as plugins and interpreted dynamically at run-

3条回答
  •  时光取名叫无心
    2020-12-19 15:22

    Python

    Since you mentioned you're in VisualStudio, the macros I wrote below may not work for you (in my experience, macros can be obnoxious cross-platform). So, here's a Python sample that you can run as a pre-build script generate the *.cpp files based on the names in a text file.

    create_classes.py

    template = """Reflection::Type * {0}::GetType() {{
        return &_type;
    }}
    
    // static type info
    
    {0} {0}::_refObj;
    
    Reflection::Type {0}::_type(_refObj, "{0}", {0}::IsAssignableFrom);
    
    Reflection::Type * {0}::Type() {{
        return &_type;
    }}
    
    bool {0}::IsAssignableFrom(Reflection::Type * type) {{
        return dynamic_cast<{0}*>(&type->RefObj()) != nullptr;
    }}
    """
    
    if __name__ == '__main__':
        with open('classes', 'r') as classes:
            for class_name in classes:
                class_name = class_name.strip()
                with open('{0}.cpp'.format(class_name), 'w') as source:
                    source.write(template.format(class_name))
    

    classes (text file)

    Blossom
    Bubbles
    Buttercup
    

    Which will create Blossom.cpp, Bubbles.cpp, and Buttercup.cpp using the template above. Getting the correct names into the 'classes' text file is up to you. :)

    I'm sure you can adapt this to split each definition across *.hpp and *.cpp, let me know if this is helpful.

    C++ Macros

    As much as I dislike macros (and I still advise against using them when possible!) here are macros that will generate your code. I haven't tested them thoroughly, so they could shoot you in the foot. They're also named poorly (unclear what the macros do from their names), but this is the idea.

    macros.cpp

    #define GET_TYPE_METHOD(X) \
        Reflection::Type * X::GetType() { return &_type; }
    
    #define GET_REF_OBJ(X) X X::_refObj;
    
    #define GET_UNDERSCORE_TYPE(X) \
        Reflection::Type X::_type(_refObj, #X, X::IsAssignableFrom);
    
    #define GET_TYPE(X) \
        Reflection::Type * X::Type() { return &_type; }
    
    #define GET_IS_ASSIGNABLE_FROM(X) \
        bool X::IsAssignableFrom(Reflection::Type * type) { return dynamic_cast(&type->RefObj()) != nullptr; }
    
    GET_TYPE_METHOD(Keeler)
    GET_REF_OBJ(Keeler)
    GET_UNDERSCORE_TYPE(Keeler)
    GET_TYPE(Keeler)
    GET_IS_ASSIGNABLE_FROM(Keeler)
    

    If you run g++ -E macros.cpp, you get the preprocessor output. Check out what the preprocessor thinks:

    $ g++ -E macros.cpp
    # 1 "macros.cpp"
    # 1 ""
    # 1 "/usr/include/stdc-predef.h" 1 3 4
    # 1 "" 2
    # 1 "macros.cpp"
    # 16 "macros.cpp"
    Reflection::Type * Keeler::GetType() { return &_type; }
    Keeler Keeler::_refObj;
    Reflection::Type Keeler::_type(_refObj, "Keeler", Keeler::IsAssignableFrom);
    Reflection::Type * Keeler::Type() { return &_type; }
    bool Keeler::IsAssignableFrom(Reflection::Type * type) { return dynamic_cast(&type->RefObj()) != nullptr; }
    

    Is this along the lines of what you were looking for?

提交回复
热议问题