2017-04-20 74 views
1

我想写一个漂亮的打印机为一个类包含一个std ::对象集,我也提供我自己的漂亮的打印机。基本上,这是我的C++代码的样子:GDB:漂亮的打印类包含STL容器

#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 
} 

我希望能够漂亮地打印类“FooContainer”的对象。所以,我想漂亮的打印机,看起来在某种程度上像这样:

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 

然而,尝试这些,GDB给我一个错误:

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

它看起来像FooContainerPrinter只能访问内部成员一个std :: set,并且不能迭代它。我会真的喜欢避免必须遍历std :: set后面的红黑树。有没有一个巧妙的诀窍来实现这一目标?

回答

0

经过一番尝试,我找到了一个非常接近的方法。我基本上使用stdlib提供的默认StdSetPrinter,但我没有用它来打印,只是为了迭代集合。我的代码看起来像现在这样:

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() 

现在,默认的漂亮印花魔术还是增加了一些样板(基本上是输出“我富容器= {...&langle;内容和rangle漂亮地打印; ...}”)但这对我来说很好。我认为它甚至能够而不是定义一个自己的children(),而是使用to_string()中的pp.children(),从而完全控制输出字符串。

它的缺点是libstdC++放置其默认漂亮打印机的路径需要放在PYTHONPATH中。

1

没有什么好的方法去做你想要的东西。主要的问题是漂亮的打印API被故意保持简单(可能有点太简单),所以它不提供可编程的方式来挑选容器 - 它只提供打印所需要的东西,有时这是有时不太一般。

但是,在这种情况下,一种可行的方法可能是推迟到std::set打印机。

也就是说,只需放下FooContainer打印机,然后再写一个Foo打印机。 A FooContainer将使用默认的gdb样式打印,封装的std::set将使用libstdC++打印机显示,并且使用您的Foo打印机显示各个元素。

如果您确实想将整个内容打印为一个长字符串,那么恐怕您必须挖掘std::set打印机并从中提取一些代码。

+0

关于Tom的最后一点,请参阅'RbtreeIterator'类型(它将GCC的RB树转换为树中所有节点上的Python迭代)和'get_value_from_Rb_tree_node'函数,它的名字就意味着它。您可能不需要从中提取代码,只需重新使用它们即可。我希望。 –

+0

这是一个好主意,但有一点需要注意的是,如果libstdC++发生变化,您的代码将来可能不得不适应。我忘记了这段代码使用了一个方便的帮助类... –

+0

感谢您的答案。不过,我想我通过劫持默认的漂亮打印机找到了我想做的事情。详情请参阅我的回答。 –