generic way to print out variable name in c++

前端 未结 6 752
难免孤独
难免孤独 2020-12-05 20:47

given a class

struct {
  int a1;
  bool a2;
  ...
  char* a500;
  ...
  char a10000;      
}

I want to print or stream out



        
相关标签:
6条回答
  • 2020-12-05 21:28

    The watch macro is one of the most useful tricks ever.

    #define watch(x) cout << (#x) << " is " << (x) << endl
    

    If you’re debugging your code, watch(variable); will print the name of the variable and its value. (It’s possible because it's built during preprocessing time.)

    0 讨论(0)
  • 2020-12-05 21:43

    It's not possible (see the other answers).

    One workaround for this is to use automatic code generation. You write the field definitions in a file and then generate the .h and .cpp files from it. I used this for a code which had around 100 classes with lots of fields. It was able to generate the code for sending them to streams (mostly debugging) and for socket communication. It's very reliable (never had to test any of those functionalities), but since it's not pure C++ it might not be the solution for you.

    0 讨论(0)
  • 2020-12-05 21:44

    The feature you're looking for is typically called reflection. It is not part of C++, since in compiled languages the information you're after (human-readable variable names) is generally not kept by the compiler. It is not needed to run the code, so there's no point in including it.

    Debuggers can often inspect either out-of-band symbol information, or symbol data kept in binaries for this very purpose, to show such names but re-doing that for this purpose is probably more work than it's worth.

    I would suggest looking for some of the many "tricks" (=solutions) to implement this yourself.

    0 讨论(0)
  • 2020-12-05 21:44

    There is no way to enumerate members of the class in C++, since there is no reflection in C++. So you cannot have access to the variable name.

    You could use pointers to members though...

    void PrintMemberValue(int MyClass::*p, MyClass const & obj)
    {
        cout << "Member has value " << obj.*p;
    }
    
    MyClass obj;
    int MyClass::*p = &MyClass::a1;
    PrintMemberValue(p, obj);
    p = &MyClass::a2;
    PrintMemberValue(p, obj);
    etc
    
    0 讨论(0)
  • 2020-12-05 21:48

    GDB can print structs. This script generates gdb script to set breakpoints and print values at specified by gdb_print locations:

    gdb-print-prepare()
    {
    
        # usage:
        # mark print points with empty standalone defines:
        # gdb_print(huge_struct);
        # gdb-print-prepare $src > app.gdb
        # gdb --batch --quiet --command=app.gdb $app
        cat  <<-EOF
        set auto-load safe-path /
        EOF
        grep --with-filename --line-number --recursive '^\s\+gdb_print(.*);' $1 | \
        while IFS=$'\t ;()' read line func var rest; do
            cat  <<-EOF
            break ${line%:}
            commands
            silent
            where 1
            echo \\n$var\\n
            print $var
            cont
            end
            EOF
        done
        cat  <<-EOF
        run
        bt
        echo ---\\n
        EOF
    }
    

    From https://gitlab.com/makelinux/lib/blob/master/snippets/gdb-print-prepare.md

    0 讨论(0)
  • 2020-12-05 21:50

    You can employ an evil macro:

    #define DUMP(a) \
        do { std::cout << #a " is value " << (a) << std::endl; } while(false)
    

    Usage example (Edit now updated with example for struct members):

    #include <iostream>
    
    #define DUMPSTR_WNAME(os, name, a) \
        do { (os) << (name) << " is value " << (a) << std::endl; } while(false)
    
    #define DUMPSTR(os, a) DUMPSTR_WNAME((os), #a, (a))
    #define DUMP(a)        DUMPSTR_WNAME(std::cout, #a, (a))
    
    struct S {
        int a1;
        float a2;
        std::string a3;
    
        std::ostream& dump(std::ostream& os)
        {
            DUMPSTR(os, a1);
            DUMPSTR(os, a2);
            DUMPSTR(os, a3);
            return os;
        }
    };
    
    int main()
    {
        S s = { 3, 3.14, "  03.1415926" };
    
        s.dump(std::cout);
    
        DUMP(s.a1);
        DUMP(s.a2);
        DUMP(s.a3);
    
        return 0;
    }
    

    See live demo on CodePad

    Why the funny macro?

    Answering the unasked question. Consider what happens if you nest the macro invocation in a conditional, or a for loop. Marshall Cline explains the rest

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