Printing C++ Objects to stderr/stdout

When your C++ projects grow a little, you may find yourself needing to log the state of objects. There are two ways of doing this (assuming that you’ll want to log the data the same way each time).

The wrong way is writing logging code that knows everything about your objects internals. E.g. if you have three

struct BoxSize {
  int width, height;
};

struct Coordinates {
  int x,y;
};


struct Box {
  Coordinates coordinates;
  BoxSize size;
};

and it is initialized as so

Box box;
box.coordinates.x = 12;
box.coordinates.y = 12;
box.size.width = 100;
box.size.height = 200;

a naive implementation of logging the state of the box would be to just extract the from the params directly.

``cpp std::cerr « “box:” « std::endl; std::cerr « “coordinates: “ « box.coordinates.x « ”,” « box.coordinates.y « std::endl; std::cerr « “size: “ « box.size.width « ”,” « box.size.height « std::endl « std::endl;


However a better implementation can be done (again assuming you want the values logged exactly the same way every time)


First you need to implement operator<< function and call it your friend. Like so:


```cpp
struct BoxSize {
  int width, height;
  friend std::ostream& operator<< (std::ostream &out, BoxSize &bs)
  {
    out << bs.width <<  "," << bs.height;
    return out;
  }
};

and the same for the coordinates:

struct Coordinates {
  int x, y;
  friend std::ostream& operator<< (std::ostream &out, Coordinates &c)
  {
        out << c.x <<  "," << c.y;
        return out;
  }
};

and finally the box:

struct Box {
  Coordinates coordinates;
  BoxSize size;
  friend std::ostream& operator<< (std::ostream &out, Box &sb)
  {
        out << "Coordinates: " << sb.coordinates << std::endl;
        out << "Size: " << sb.size << std::endl;
        return out;
  }
};

now the logging of the object can be done in one line - and you never have to worry about typing it the right way… And even better, if any of the structs internals change, their own code will need to change to log the right values… Not every consumer of the actual objects.

std::cerr << "box: " << std::endl << box << std::endl;