GDB: класс Pretty-Print, содержащий контейнер STL

Я пытаюсь написать симпатичный принтер для класса, содержащего набор std :: set, для которого я также поставляю свой собственный симпатичный принтер. По сути, так выглядит мой код на C ++:

#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 самостоятельно. Есть ли хитрый трюк для достижения этого?

2

Решение

Там нет хорошего способа сделать именно то, что вы хотите. Основная проблема заключается в том, что API-интерфейс для симпатичной печати был преднамеренно простым (возможно, слишком простым), и поэтому он не обеспечивает программируемый способ разборки контейнеров — он предоставляет только то, что необходимо для печати, что иногда менее общий.

Однако в этой ситуации одним из жизнеспособных подходов может быть std::set принтер.

То есть просто бросьте FooContainer принтер, и просто напишите Foo принтер. FooContainer будет напечатан с использованием стиля GDB по умолчанию, прилагается std::set будет отображаться с помощью принтера libstdc ++, а отдельные элементы будут отображаться с помощью вашего Foo принтер.

Если вы действительно хотите распечатать все содержимое в виде одной длинной строки, то, боюсь, вам придется выкопать std::set принтер и извлечь из него код.

2

Другие решения

После некоторых попыток я нашел способ, который подходит очень близко. Я в основном использую стандартный StdSetPrinter, предоставляемый с stdlib, но я не использую его для печати, просто для итерации набора. Мой код выглядит следующим образом:

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

Теперь, по умолчанию, волшебство красивой печати все еще добавляет шаблон (в основном это выводит «My Foo Container = {… 〈pretty-print of content〉…}»), но это меня устраивает. Я думаю, что это было бы даже в состоянии не определить собственный children (), но лучше использовать pp.children () внутри to_string () и, таким образом, иметь полный контроль над выходной строкой.

Недостатком является то, что путь, в который libstdc ++ помещает свои симпатичные принтеры по умолчанию, должен быть в PYTHONPATH.

1

По вопросам рекламы [email protected]