finite graygreen
finite graygreen

Reputation: 335

A better #define print std::cout<<boost::format

To quickly insert brief debug statements I would like to turn

print("%d %d %s") % i % j % str;

into the more verbose

std::cout << boost::format("%d %d %s") % i % j % str << std::endl;

The mentioned #define print std::cout<<boost::format does not have the endl, so even if I add a "\n" to the string the buffers are not flushed if a crash occurs on the next line.

The more C++-ish approach to have print("string) return an xPrint instance and overload xPrint::operator% does not work because I have no way of knowing when the last % call has been made and it is time to print the resulting format string.

Note: I need boost::format, so a printf/fflush won't do, and I'd like the resulting syntax to be brief.

Upvotes: 0

Views: 329

Answers (1)

jasal
jasal

Reputation: 1053

I would suggest something like

#define print(x) std::cout << (x) << std::endl

which allows you to do

print(boost::format("%s") % str);

If you really insist on the brief version given above the closest thing I can come up with is this:

#include <iostream>
#include <boost/format.hpp>

class Forwarder
{
public:
  Forwarder(const std::string& s)
    : f(s)
  {}

  template <typename T>
  Forwarder& operator%(const T& t)
  {
    f % t;
    return *this;
    // You could even return a reference to f here instead if you wanted
  }

  ~Forwarder()
  {
    std::cout << f << std::endl;
  }

private:
  boost::format f;
};

#define print(x, y) { Forwarder f(x); f % y; }

int main()
{
  std::string str("Hallo");
  int i = 123, j = 456;
  print("%s %d %d", str % i % j);
}

EDIT Here are some more (potentially dangerous!) ideas for hacking such a print statement. Code below is just to show the concepts and won't compile as is. Use at your own risk!

a) Add a terminating statement to Forwarder by adding a specialization for operator% instead of using the destructor to trigger printing:

Define helper struct as terminator (better be in a namespace, but you get the idea...):

struct END {};

Specialize template:

template <>
Forwarder& Forwarder::operator%<END>(const END& t)
{
  std::cout << f << std::endl;
  return *this;
}

Usage:

print("%s %d %d") % str % i % j % END;

b) Use an operator with less strict binding and right to left associativity. You'd have to introduce a helper type though which could be some kind of logging target.

void operator<<=(Logger& l, const Forwarder& f) { ... }

Usage:

DebugLogger <<= Forwarder("%s %d %d") % str % i % j;

c) The same as above but using the comma operator (yuck!) which has left to right associativity.

void operator,(const Forwarder& f, Logger& l) { ... }

Usage:

Forwarder("%s %d %d") % str % i % j, DebugLogger;

Upvotes: 2

Related Questions