Indeed, this can be done if the library or your code provides overloads for operator<<and operator>>for its operation. A simple example of how this can be done:
class transformer {
public:
virtual std::iostream& transform(std::iostream&) = 0;
};
class noise : public transformer {
public:
virtual std::iostream& transform(std::iostream&) {
/* extract, change and put into again */
}
};
class echo : public transformer {
public:
virtual std::iostream& transform(std::iostream&) {
/* extract, change and put into again */
}
};
std::iostream& operator>>(std::iostream& io, transformer& ts) {
return ts.transform(io);
}
int main() {
std::stringstream data;
std::ifstream file("sound.wav");
noise n; echo e;
data << file.rdbuf();
data >> n >> e;
/* pipelined data now ready to be played back */
}
std::istream , , . , std::iostream . , → call .
, expression template. , , operator>>, , , :
typedef transform< echo< noise< istream > > > pipeline;
std::ifstream file("file.wav");
pipeline pipe(file);
int byte = pipe.get();
. . . , typedef , . . , , , Boost.Iostreams(. ). , , , :):
#include <iostream>
template<typename T>
struct transformer {
int get() {
return static_cast<T*>(this)->read();
}
};
struct echot {
template<typename Chain>
struct chain : transformer< chain<Chain> > {
Chain c;
int read() {
return c.get() + 1;
}
chain(Chain const& c):c(c) { }
};
} echo;
struct noiset {
template<typename Chain>
struct chain : transformer< chain<Chain> > {
Chain c;
int read() {
return c.get() * 2;
}
chain(Chain c):c(c) { }
};
} noise;
template<typename T>
typename T::template chain<std::istream&> operator>>(std::istream& is, T) {
return typename T::template chain<std::istream&>(is);
}
template<typename T, typename U>
typename U::template chain<T> operator>>(T t, U u) {
return typename U::template chain<T>(t);
}
int main() {
std::cout << (std::cin >> echo >> noise).get() << std::endl;
}
0 ASCII 48, 1 2, 98, , , . , , - , . , , .
Boost iostreams, . , - . Boost.Iostreams