Click here to Skip to main content
Licence 
First Posted 8 Jan 2005
Views 35,015
Bookmarked 21 times

Piping between Functions

By | 8 Jan 2005 | Article
A trivial way to pipe the cout from one function to the cin of another.

Introduction

This article describes how we can pipe functions together as we would program on the command line.

Filters

A filter is a program which takes its input from the standard input stream (std::cin) and places its output to the standard output stream (std::cout). The reason for writing a program as a filter is that it can be used from the OS shell, to redirect its output to a file or device. Filters can also be piped together, which means redirecting the output from one program to the input of the other. This makes programs written as filters highly flexible and hence more reusable.

Functions as Filters

A function often behaves like a filter, taking some input from the standard input and outputting to the standard output. So there is no reason why we can't treat a function like we would treat a filter, and redirect its standard output to the standard input of another.

Example

Let's say we have the following functions, which operate on the cin and cout streams:

void HelloWorld() { 
  cout << "hello world" << endl;  
}

void CountChars() {
  string s;
  getline(cin, s);
  cout << static_cast<int>(s.size()) << endl;
}

By overloading the greater-than operator (>), we can now write a new function, which outputs the number of characters output onto the stream by HelloWorld().

void CountCharsInHelloWorld() {
  filter(HelloWorld) > filter(CountChars);
}

The Code

The code to accomplish this functionality is quite simple.

#include <iostream>
#include <sstream>

using namespace std;

typedef void(*procedure)();

class filter {
  public:
    filter(procedure x) : proc(x) { }
    void operator()(istream& in, ostream& out) {
      streambuf* inbuf = cin.rdbuf();
      streambuf* outbuf = cout.rdbuf();
      cin.rdbuf(in.rdbuf());
      cout.rdbuf(out.rdbuf());
      proc();
      cin.rdbuf(inbuf);
      cout.rdbuf(outbuf);
    }
  private:
    procedure proc;
};

void operator>(filter f1, filter f2) {
  stringstream s;
  f1(cin, s);
  s.seekg(0);
  f2(s, cout);
}

Summary

This is a very simple technique, but it can be used to write our code in a manner which is much easier to reuse. All of those UNIX programmers weren't wrong!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Christopher Diggins

Architect
Autodesk
Canada Canada

Member

Follow on Twitter Follow on Twitter
I've been programming personal computers since my I got my first Atari 400 in 1980. I currently work at Autodesk as an SDK specialist.
 
One of my passions is the design and implementation of programming languages. My current project is the Jigsaw library which includes a parsing engine and other utilities for implementing programming languages in C#.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
Generalpiping two functions/programs Pinmemberav283616:46 25 Apr '07  
GeneralC++ VS 2003 PinmemberLorad3:48 10 Jan '05  
GeneralRe: C++ VS 2003 Pinmembercdiggins4:31 10 Jan '05  
GeneralNice Hack! PinmemberMr.Prakash16:53 8 Jan '05  
GeneralRe: Nice Hack! Pinmembercdiggins17:05 8 Jan '05  
GeneralRe: Nice Hack! PinmemberDon Clugston14:19 9 Jan '05  
Chris, you're publishing an impressive number of articles!
Are you doing this full-time, or are they things you've developed over the years?
 
>I would argue that it doesn't really change the meaning of the operator, because an operator only has meaning with regards to its context, i.e. the types of the parameters passed to it.
 
From the compiler's point of view, that's true. But it's very surprising from a programmer's viewpoint.
 
> It is also worthwhile to point out that streams overload >> and << which have separate meanings for ints.
 
I think that's a special case. Because it was introduced very early in the history of C++, it became a de-facto standard. In fact, I suspect that << is used more often for stream output than for bit shifts. The effect of this is that when I encounter << or >>, I am expecting it to be overloaded in one of those two ways. But when I see |, I expect it to be either the builtin OR function, or an overloaded operator with the same syntax. I don't expect it to be a pipe operator. When I see the line
 
filter(HelloWorld) | filter(CountChars);
 
I think, "these are two functions returning bool. There's a bug: the author probably left out a 'return' at the start of the line." I certainly would not expect to look for an overloaded | function. The only other special case is + for string concatenation. Otherwise, I think operators should only be used for mathematical operations (eg, + should be associative and commutative).
 
Great trick, but I think you would be better to use >> instead of |.

GeneralRe: Nice Hack! Pinmembercdiggins17:06 9 Jan '05  
GeneralRe: Nice Hack! PinmemberDon Clugston18:08 9 Jan '05  
GeneralRe: Nice Hack! Pinmembercdiggins4:36 10 Jan '05  
GeneralRe: Nice Hack! Pinmembercdiggins3:40 12 Jan '05  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web01 | 2.5.120528.1 | Last Updated 8 Jan 2005
Article Copyright 2005 by Christopher Diggins
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid