有没有办法使用这些运算符来输入和输出二进制数据?我想这样做的原因是它使代码可读。例如:infile >> filedecrypter >> metadataparser >> audiodecoder >> effects >> soundplayer;
4 回答
需要明确的是,您是否打算复制 iostream 的语义?因为看起来你提出了一些不同的建议。在您给出的示例中:
infile >> filedecrypter >> metadataparser >> audiodecoder >> effects >> soundplayer;
在 iostreams 中,这里的意思是从 infile 读取到 filedecrypter 直到你得到空白,然后从 infile 读取到 metadataparser 直到更多的空白,等等。
看起来您提出了一些不同的建议,其中 metadataparser 从 filedecrypter 读取,从 metadataparser 读取 audiodecoder 等。在这种情况下,我认为您的问题的答案需要稍微限定一下。
你能用运算符 >>来表达这个结构吗?可能是的。
您可以为此使用 iostreams吗?可能不是。
我建议您在说 A >> B 时澄清它的含义。也许首先将其表达为常规方法而不是运算符重载,这可能会澄清问题。
operator<<
如果库或您的代码为其工作提供重载,那么确实可以做到operator>>
这一点。关于如何做到这一点的简单示例:
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 */
}
使用 pure 的问题std::istream
在于您会阅读,但是您无法将转换后的数据放回管道中的下一步。因此我在std::iostream
这里使用。这种方法似乎效率不高,因为每个 operator>> 调用都会提取整个数据,然后再次放入。
要拥有一种更高效的流式传输方式,那就是创建一个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
当然可以。只需定义您自己的 operator>> 和 operator<< 以便他们做“正确的事”...
我会这样做,所以我会在类中有方法,比如 toStream(ostream& os) 和 fromStream(istream& ),然后定义
istream& operator>> (istream& is, T& t)
{
t.fromStream(is);
return t;
}
ostream& operator<< (ostream& os, const T& t)
{
t.toStream(os);
return t;
}
无需使用流来移动数据。您可以创建自己的类来执行此操作。这显示了一个例子。显然,Decrypt 和 MetaDataParser 类可以是具有虚函数的抽象基类,以允许将各种功能插入在一起。
#include <iostream>
#include <istream>
using namespace std;
class Data2
{
};
class Data3
{
};
class Decrypt
{
};
class MetaDataParser
{
};
Data2& operator>>(istream& in, Decrypt& decrypt)
{
return *new Data2;
}
Data3& operator>>(Data2& d2, MetaDataParser& mdp)
{
return *new Data3;
}
int main()
{
Decrypt decrypt;
MetaDataParser mdp;
cin >> decrypt >> mdp;
}