2017-04-20 1 views
1

Ich versuche, einen hübschen Drucker für eine Klasse zu schreiben, die ein std :: Set von Objekten enthält, für die ich auch meinen eigenen hübschen Drucker anbiete. Sehr im Grunde, das ist, wie mein C++ Code wie folgt aussieht:GDB: Pretty-Print-Klasse mit STL-Container

#include <set> 
#include <iostream> 
#include <cassert> 

class Foo { 
public: 
    int x; 

    bool operator<(const Foo & rhs) const { 
    return this->x < rhs.x; 
    } 
}; 

class FooContainer { 
public: 
    std::set<Foo> content; 
}; 

int main(int argc, char **argv) { 
    FooContainer c; 
    Foo f1 {1}; 
    Foo f2 {2}; 
    c.content.insert(f1); 
    c.content.insert(f2); 

    assert(false); // hand over to gdb 
} 

Ich mag Pretty-Print-Objekte der Klasse „FooContainer“ in der Lage sein. Also, ich ziemlich Drucker wollen, die irgendwie wie diese aussehen:

class FooPrinter(object): 
    def __init__(self, val): 
     self.val = val 

    def to_string(self): 
     return "X: " + str(self.val['x']) 

class FooContainerPrinter(object): 
    def __init__(self, val): 
     self.val = val 

    def to_string(self): 
     res = "" 
     for foo in self.val['content']: 
      res += " " + FooPrinter(foo).to_string() 
     return res 

jedoch versucht, diese, gibt GDB mir ein Fehler:

(gdb) p c 
Python Exception <class 'TypeError'> 'gdb.Value' object is not iterable: 
$7 = 

Es sieht aus wie die FooContainerPrinter nur Zugriff auf die internen Mitglieder hat eines std :: set und kann nicht iterieren. Ich würde wirklich gerne vermeiden, den Rot-Schwarz-Baum hinter diesem Std durchqueren zu müssen :: setze mich. Gibt es einen netten Trick, um dies zu erreichen?

Antwort

0

Nach einigen Versuchen habe ich einen Weg gefunden, der sehr nahe kommt. Ich benutze grundsätzlich den Standard-StdSetPrinter, der mit der stdlib geliefert wird, aber ich benutze ihn nicht zum Drucken, nur zum Iterieren des Satzes. Mein Code sieht wie folgt nun:

from libstdcxx.v6.printers import StdSetPrinter 

class FooPrinter(object): 
    def __init__(self, val): 
     self.val = val 

    def to_string(self): 
     return "X: " + str(self.val['x']) 

class FooContainerPrinter(object): 
    def __init__(self, val): 
     self.val = val 

    def to_string(self): 
     return "My Foo Container" 

    def children(self): 
     pp = StdSetPrinter("dummy", self.val['content']) 
     return pp.children() 

Nun wird die Standard ziemlich Druck Magie noch einige Textvorschlag fügt hinzu (im Grunde gibt sie "My Foo Container = {... & langle; Pretty-Print des Inhalts & rangle; ...}") aber das ist in Ordnung mit mir. Ich denke, es wäre sogar in der Lage nicht definieren Sie eine eigene Kinder(), sondern verwenden Sie die pp.children() innerhalb to_string() und haben somit die volle Kontrolle über die Ausgabe-String.

Es hat den Nachteil, dass der Pfad, in dem libstdC++ seine standardmäßigen hübschen Drucker platziert, im PYTHONPATH enthalten sein muss.

1

Es gibt keinen guten Weg, genau das zu tun, was Sie wollen. Das Hauptproblem ist, dass die Pretty-Printing-API absichtlich einfach gehalten wurde (vielleicht ein bisschen zu einfach) und daher keine programmierbare Möglichkeit bietet, Container auseinander zu nehmen - sie liefert nur genau das, was zum Drucken benötigt wird, was manchmal der Fall ist weniger allgemein.

In dieser Situation könnte jedoch ein praktikabler Ansatz sein, auf den std::set Drucker zu verzichten.

Das ist, einfach den FooContainer Drucker fallen lassen, und schreiben Sie einfach einen Foo Drucker. A FooContainer wird mit dem Standard-GDB-Format gedruckt, die beigefügte std::set wird mit dem Drucker libstdC++ angezeigt, und die einzelnen Elemente werden mit Ihrem Foo Drucker angezeigt.

Wenn Sie wirklich den gesamten Inhalt als eine lange Zeichenfolge ausdrucken möchten, dann, ich fürchte, Sie müssen den std::set Drucker ausgraben und etwas Code daraus extrahieren.

+0

Zu Toms letztem Punkt siehe den 'RbtreeIterator'-Typ (der GCCs RB-Bäume in Python-Iterablen über alle Knoten in der Baumstruktur umwandelt) und die' get_value_from_Rb_tree_node'-Funktion, die ihren Namen impliziert. Sie müssen wahrscheinlich keinen Code aus ihnen extrahieren, sondern sie einfach wiederverwenden. Ich hoffe. –

+0

Das ist eine gute Idee, mit der Einschränkung, dass es in Zukunft möglich ist, dass Ihr Code angepasst werden muss, wenn es Änderungen in libstdC++ gibt. Ich hatte vergessen, dass dieser Code eine bequeme Helferklasse verwendete ... –

+0

Danke für die Antworten. Ich denke jedoch, dass ich einen Weg gefunden habe, das zu tun, was ich möchte, indem ich den Standard-Pretty-Drucker entführe. Siehe meine Antwort für Details. –