Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write a function wrapper for cout that allows for expressive syntax?

Tags:

c++

cout

wrapper

I'd like to wrap std::cout for formatting, like so:

mycout([what type?] x, [optional args]) {
    ... // do some formatting on x first
    std::cout << x;
}

and still be able to use expressive syntax like

mycout("test" << i << endl << somevar, indent)

instead of being forced to be more verbose like

mycout(std::stringstream("test") << i ...)

How can I implement this? What type to make x?

Edit: added consideration for optional arguments

like image 293
mchen Avatar asked May 08 '13 15:05

mchen


3 Answers

How about this:

struct MyCout {};

extern MyCout myCout;

template <typename T>
MyCout& operator<< (MyCout &s, const T &x) {
  //format x as you please
  std::cout << x;
  return s;
}

And put MyCout myCout; into any one .cpp file.

You can then use myCout like this:

myCout << "test" << x << std::endl;

And it will call the template operator<< which can do the formatting.

Of course, you can also provide overloads of the operator for special formatting of specific types if you want to.

EDIT

Apparently (thanks to @soon), for standard manipulators to work, a few more overloads are necessary:

MyCout& operator<< (MyCout &s, std::ostream& (*f)(std::ostream &)) {
  f(std::cout);
  return s;
}

MyCout& operator<< (MyCout &s, std::ostream& (*f)(std::ios &)) {
  f(std::cout);
  return s;
}

MyCout& operator<< (MyCout &s, std::ostream& (*f)(std::ios_base &)) {
  f(std::cout);
  return s;
}

EDIT 2

I may have misunderstoor your original requirements slightly. How about this (plus the same manipulator overloads as above):

struct MyCout
{
  std::stringstream s;

  template <typename T>
  MyCout& operator << (const T &x) {
    s << x;
    return *this;
  }

  ~MyCout() {
    somehow_format(s);
    std::cout << s.str();
  }
};

int main() {
  double y = 1.5;
  MyCout() << "test" << y;
}
like image 61
Angew is no longer proud of SO Avatar answered Nov 16 '22 01:11

Angew is no longer proud of SO


This comes easy with variadic template arguments:

template <class T>
void print(T t)
{
    std::cout << t;
}

template <class T, class... Args>
void print(T t, Args... args)
{
    std::cout << t << std::endl;
    print(args...);
}

int main()
{
    std::cout << std::boolalpha;
    print(3, 's', true, false);
}

Output:

3
s
true
false

Live Demo

like image 4
David G Avatar answered Nov 16 '22 00:11

David G


A variation from the answers:

#include <iostream>

using namespace std;

class MyCout 
{
public:
  MyCout& operator()(bool indent) { 
    if ( indent ) cout << '\t'; 
    return *this;
  }

  template<class T>
  MyCout& operator<<(T t) {
    cout << t;
    return *this;
  }

  MyCout& operator<<(ostream& (*f)(ostream& o)) {
    cout << f;
    return *this;
  };
};

int main()
{
  MyCout mycout;
  int x = 10;
  mycout(true)<< "test" << 2 << x << endl ;
}
like image 1
Amadeus Avatar answered Nov 15 '22 23:11

Amadeus