2017-04-20 117 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

感謝您的答案。不過,我想我通過劫持默認的漂亮打印機找到了我想做的事情。詳情請參閱我的回答。 –