How can I add reflection to a C++ application?

前端 未结 28 1606
感动是毒
感动是毒 2020-11-21 11:25

I\'d like to be able to introspect a C++ class for its name, contents (i.e. members and their types) etc. I\'m talking native C++ here, not managed C++, which has reflection

相关标签:
28条回答
  • 2020-11-21 11:52

    You can achieve cool static reflection features for structs with BOOST_HANA_DEFINE_STRUCT from the Boost::Hana library.
    Hana is quite versatile, not only for the usecase you have in mind but for a lot of template metaprogramming.

    0 讨论(0)
  • 2020-11-21 11:53

    Reflection is essentially about what the compiler decided to leave as footprints in the code that the runtime code can query. C++ is famous for not paying for what you don't use; because most people don't use/want reflection, the C++ compiler avoids the cost by not recording anything.

    So, C++ doesn't provide reflection, and it isn't easy to "simulate" it yourself as general rule as other answers have noted.

    Under "other techniques", if you don't have a language with reflection, get a tool that can extract the information you want at compile time.

    Our DMS Software Reengineering Toolkit is generalized compiler technology parameterized by explicit langauge definitions. It has langauge definitions for C, C++, Java, COBOL, PHP, ...

    For C, C++, Java and COBOL versions, it provides complete access to parse trees, and symbol table information. That symbol table information includes the kind of data you are likely to want from "reflection". If you goal is to enumerate some set of fields or methods and do something with them, DMS can be used to transform the code according to what you find in the symbol tables in arbitrary ways.

    0 讨论(0)
  • 2020-11-21 11:55

    There are two kinds of reflection swimming around.

    1. Inspection by iterating over members of a type, enumerating its methods and so on.

      This is not possible with C++.
    2. Inspection by checking whether a class-type (class, struct, union) has a method or nested type, is derived from another particular type.

      This kind of thing is possible with C++ using template-tricks. Use boost::type_traits for many things (like checking whether a type is integral). For checking for the existance of a member function, use Is it possible to write a template to check for a function's existence? . For checking whether a certain nested type exists, use plain SFINAE .

    If you are rather looking for ways to accomplish 1), like looking how many methods a class has, or like getting the string representation of a class id, then i'm afraid there is no Standard C++ way of doing this. You have to use either

    • A Meta Compiler like the Qt Meta Object Compiler which translates your code adding additional meta informations.
    • A Framework constisting of macros that allow you to add the required meta-informations. You would need to tell the framework all methods, the class-names, base-classes and everything it needs.

    C++ is made with speed in mind. If you want high-level inspection, like C# or Java has, then I'm afraid i have to tell you there is no way without some effort.

    0 讨论(0)
  • 2020-11-21 11:57

    I think you might find interesting the article "Using Templates for Reflection in C++" by Dominic Filion. It is in section 1.4 of Game Programming Gems 5. Unfortunately I dont have my copy with me, but look for it because I think it explains what you are asking for.

    0 讨论(0)
  • 2020-11-21 11:57

    If you're looking for relatively simple C++ reflection - I have collected from various sources macro / defines, and commented them out how they works. You can download header files from here:

    https://github.com/tapika/TestCppReflect/blob/master/MacroHelpers.h

    set of defines, plus functionality on top of it:

    https://github.com/tapika/TestCppReflect/blob/master/CppReflect.h https://github.com/tapika/TestCppReflect/blob/master/CppReflect.cpp https://github.com/tapika/TestCppReflect/blob/master/TypeTraits.h

    Sample application resides in git repository as well, in here: https://github.com/tapika/TestCppReflect/

    I'll partly copy it here with explanation:

    #include "CppReflect.h"
    using namespace std;
    
    
    class Person
    {
    public:
    
        // Repack your code into REFLECTABLE macro, in (<C++ Type>) <Field name>
        // form , like this:
    
        REFLECTABLE( Person,
            (CString)   name,
            (int)       age,
    ...
        )
    };
    
    void main(void)
    {
        Person p;
        p.name = L"Roger";
        p.age = 37;
    ...
    
        // And here you can convert your class contents into xml form:
    
        CStringW xml = ToXML( &p );
        CStringW errors;
    
        People ppl2;
    
        // And here you convert from xml back to class:
    
        FromXml( &ppl2, xml, errors );
        CStringA xml2 = ToXML( &ppl2 );
        printf( xml2 );
    
    }
    

    REFLECTABLE define uses class name + field name with offsetof - to identify at which place in memory particular field is located. I have tried to pick up .NET terminology for as far as possible, but C++ and C# are different, so it's not 1 to 1. Whole C++ reflection model resides in TypeInfo and FieldInfo classes.

    I have used pugi xml parser to fetch demo code into xml and restore it back from xml.

    So output produced by demo code looks like this:

    <?xml version="1.0" encoding="utf-8"?>
    <People groupName="Group1">
        <people>
            <Person name="Roger" age="37" />
            <Person name="Alice" age="27" />
            <Person name="Cindy" age="17" />
        </people>
    </People>
    

    It's also possible to enable any 3-rd party class / structure support via TypeTraits class, and partial template specification - to define your own TypeTraitsT class, in similar manner to CString or int - see example code in

    https://github.com/tapika/TestCppReflect/blob/master/TypeTraits.h#L195

    This solution is applicable for Windows / Visual studio. It's possible to port it to other OS/compilers, but haven't done that one. (Ask me if you really like solution, I might be able to help you out)

    This solution is applicable for one shot serialization of one class with multiple subclasses.

    If you however are searching for mechanism to serialize class parts or even to control what functionality reflection calls produce, you could take a look on following solution:

    https://github.com/tapika/cppscriptcore/tree/master/SolutionProjectModel

    More detailed information can be found from youtube video:

    C++ Runtime Type Reflection https://youtu.be/TN8tJijkeFE

    I'm trying to explain bit deeper on how c++ reflection will work.

    Sample code will look like for example this:

    https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/testCppApp.cpp

    c.General.IntDir = LR"(obj\$(ProjectName)_$(Configuration)_$(Platform)\)";
    c.General.OutDir = LR"(bin\$(Configuration)_$(Platform)\)";
    c.General.UseDebugLibraries = true;
    c.General.LinkIncremental = true;
    c.CCpp.Optimization = optimization_Disabled;
    c.Linker.System.SubSystem = subsystem_Console;
    c.Linker.Debugging.GenerateDebugInformation = debuginfo_true;
    

    But each step here actually results in function call Using C++ properties with __declspec(property(get =, put ... ).

    which receives full information on C++ Data Types, C++ property names and class instance pointers, in form of path, and based on that information you can generate xml, json or even serialize that one over internet.

    Examples of such virtual callback functions can be found here:

    https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/VCConfiguration.cpp

    See functions ReflectCopy, and virtual function ::OnAfterSetProperty.

    But since topic is really advanced - I recommend to check through video first.

    If you have some improvement ideas, feel free to contact me.

    0 讨论(0)
  • 2020-11-21 11:58

    And I would love a pony, but ponies aren't free. :-p

    http://en.wikibooks.org/wiki/C%2B%2B_Programming/RTTI is what you're going to get. Reflection like you're thinking about -- fully descriptive metadata available at runtime -- just doesn't exist for C++ by default.

    0 讨论(0)
提交回复
热议问题