ruediger / Boost-Pretty-Printer

GDB Pretty Printers for Boost
197 stars 61 forks source link

Suppress Boost.Operators #11

Closed mrzv closed 8 years ago

mrzv commented 10 years ago

I don't know if it's possible, but it would be great to suppress printing Boost.Operators types. Right now if one creates a class that inherits from boost::addable, boost::multipliable, etc, all those classes show up when pretty printing an instance of the class. But that information is practically useless.

mateidavid commented 9 years ago

Can you write a short example of what you mean?

mrzv commented 9 years ago
#include <boost/operators.hpp>
#include <boost/array.hpp>

template<size_t D, typename Real = double>
struct Point:
    boost::addable< Point<D,Real>,
    boost::subtractable< Point<D,Real>,
    boost::dividable2< Point<D, Real>, Real,
    boost::multipliable2< Point<D, Real>, Real > > > >,
    public boost::array<Real, D>
{
    public:
        Point&          operator+=(const Point& p)                  { for (size_t i = 0; i < D; ++i) (*this)[i] += p[i]; return *this; }
        Point&          operator-=(const Point& p)                  { for (size_t i = 0; i < D; ++i) (*this)[i] -= p[i]; return *this; }
        Point&          operator/=(Real r)                          { for (size_t i = 0; i < D; ++i) (*this)[i] /= r;    return *this; }
        Point&          operator*=(Real r)                          { for (size_t i = 0; i < D; ++i) (*this)[i] *= r;    return *this; }
};

int main()
{
    Point<2>    p;
    p[1] = 0;
}

Now stopping at the second line of main in the debugger, and saying print p, I get:

(gdb) print p
$1 = {<boost::addable<Point<2, double>, boost::subtractable<Point<2, double>, boost::dividable2<Point<2, double>, double, boost::multipliable2<Point
<2, double>, double, boost::detail::empty_base<Point<2, double> > > >, boost::detail::empty_base<Point<2, double> >, boost::detail::true_t>, boost::
detail::empty_base<Point<2, double> >, boost::detail::true_t>> = {<boost::addable1<Point<2, double>, boost::subtractable<Point<2, double>, boost::di
vidable2<Point<2, double>, double, boost::multipliable2<Point<2, double>, double, boost::detail::empty_base<Point<2, double> > > >, boost::detail::e
mpty_base<Point<2, double> >, boost::detail::true_t> >> = {<boost::subtractable<Point<2, double>, boost::dividable2<Point<2, double>, double, boost:
:multipliable2<Point<2, double>, double, boost::detail::empty_base<Point<2, double> > > >, boost::detail::empty_base<Point<2, double> >, boost::deta
il::true_t>> = {<boost::subtractable1<Point<2, double>, boost::dividable2<Point<2, double>, double, boost::multipliable2<Point<2, double>, double, b
oost::detail::empty_base<Point<2, double> > > > >> = {<boost::dividable2<Point<2, double>, double, boost::multipliable2<Point<2, double>, double, bo
ost::detail::empty_base<Point<2, double> > > >> = {<boost::multipliable2<Point<2, double>, double, boost::detail::empty_base<Point<2, double> > >> =
 {<boost::detail::empty_base<Point<2, double> >> = {<No data fields>}, <No data fields>}, <No data fields>}, <No data fields>}, <No data fields>}, <
No data fields>}, <No data fields>}, <boost::array<double, 2>> = {6.9533558074895536e-310, 0}, <No data fields>}

Everything but the final {6.9533558074895536e-310, 0} is noise.

mateidavid commented 9 years ago

So one way would be to print only the 2nd subclass of Point. With the latest pull request, you could try:

py boost.add_trivial_printer('Point', lambda x: x.cast(x.type.fields()[1].type))

This avoids dealing with boost::addable and so on, but achieves what you need.

mrzv commented 9 years ago

This looks like a customized solution for my specific example. It's helpful, but from the point of view of your pretty printer, a generic solution would be much nicer. (Not sure if it's possible though.)

mateidavid commented 9 years ago

I'm not sure it's possible either. I don't know how to control how gdb prints the type of the base class while printing a given value. Initially I thought that's what type printers do. But look at this:

# file a.cpp
struct A {};
struct B : public A {};
A a;
B b;
void done() {}
int main() { done(); }

# file a.gdb
b done
r
ptype a
ptype b
p a
p b
py boost.add_trivial_printer("A", lambda x: str())
py boost.add_trivial_type_printer("A", lambda t: "xoxo")
ptype a
ptype b
p a
p b
q

g++ -std=c++11 -O0 -g3 -ggdb -Wall -Wextra -pedantic a.cpp -o a
gdb a -x a.gdb

The output I get:

type = struct A {
    <no data fields>
}
type = struct B : public A {
}
$1 = {<No data fields>}
$2 = {<A> = {<No data fields>}, <No data fields>}
type = xoxo
type = struct B : public xoxo {
}
$3 = 
$4 = {<A> = , <No data fields>}

So it looks like gdb uses the type printer for ptype a, and for ptype b because A is a base class of B. However, it still prints A, ignoring the type printer, when printing the value b. This could be a deficiency of the API.

Note: I added add_trivial_type_printer to the pull request.

mrzv commented 9 years ago

Hm, that is unfortunate. I wonder if it's worth bringing to the attention of gdb developers.

mateidavid commented 9 years ago

http://thread.gmane.org/gmane.comp.gdb.devel/35439

mateidavid commented 8 years ago

This generated no reaction on the mailing list.