
If it really were possible to reuse existing code, as you orginally suggested, then it would be a clear win. However, I haven't yet seen an example of a pre-existing procedure which meets the requirements of the proc_as_filter class. Therefore, I first must decide whether writing a filter as a function which reads from standard input and writes to standard output is ever the best way to write a filter, given the other choices that the library provides. You clearly think the answer is yes, but I'd like to see some examples.
Second, is there any reason to prefer functions with the signature
void (*) () [A]
This is too much strict to force the uses of cin and cout... Any other possible uses would require either to redirect inputs (which might not always be possible particulary if there are multiple thread or if some code assumes that cin or cout is the standard output and can be used freely).
over member functions taking references to an input stream and an output stream:
struct myfilter { void filter(std::istream&, std::ostream&); [B] };
This is more in keeping with the reset of the library.
This is better, but why not uses operator() instead of a named function since it would allows us to uses ordinary function of function object and it will works well with boost::function.
Finally, why shouldn't the signature be:
struct myfilter { template<typename Source, typename Sink> void filter(Source& src, Sink& snk); [C] };
?
This, combined with my suggestion of using operator() would be the best solution in my opinion. But if the Source and Sink can have arbitrary type we should have a bunch of traits that would allows the code to works with most or all type of Source and Sink. OTOH, if someone only need to support one kind of stream in it algorithm then it might prefer to implement the non-template version.
I expect the answer is that you want to be able to use formatting i/o functions in the implementation of filter(). Here, again, I'd like to see some examples to prove that it is useful.
Personally, I'd prefer [C], and I'd like to change the specification so that instead of filter() consuming all the characters in src, it reads some source source characters from src, writes some characters to snk and returns a status code, e.g. partial, eof or ok.
However, I should be able to extend it so that if a chain contains both a source and a sink, boost::io::copy is invoked. E.g.,
source() | filter1() | filter2() | filter3() | sink()
would be equivalent to
filtering_ostream out(filter1() | filter2() | filter3() | sink()); boost::io::copy(source, out);
If I can make this work, and there are no objections, I'll add it.
This is what I am ultimately striving for. Is there any reason why the source() and sink() can not be assumed to be cin and cout respectively when absent?
Yes. When you use the pipe operator you don't always want to form a complete chain:
filtering_ostream out(filter1() | filter2() | filter3()); out.push(sink());
Well passing filters to the constructor might be more limitating that working with objects. So I thing we should be able to do something like: filtering_ostream out; out < cin; out | filter1() | filter2(); out | filter3(); out > cout; Philippe