これらの演算子を使用してバイナリ データを入力および出力する方法はありますか? これを行う理由は、コードを読みやすくするためです。例: infile >> filedecrypter >> metadataparser >> audiodecoder >> Effects >> soundplayer;
4 に答える
明確にするために、iostream のセマンティクスを複製するつもりですか? あなたが何か違うものを提案しているように見えるからです。あなたが与える例では:
infile >> filedecrypter >> metadataparser >> audiodecoder >> effects >> soundplayer;
iostream では、ここでの意味は、空白になるまで infile から filedecrypter に読み込み、さらに空白になるまで infile から metadataparser に読み込むことです。
metadataparser が filedecrypter から読み取り、audiodecoder を metadataparser から読み取るなど、別のものを提案しているようです。その場合、質問への回答を少し修飾する必要があると思います。
演算子 >>を使用してこの構造を表現できますか? おそらくそうです。
これにiostream を使用できますか? おそらくそうではありません。
A >> B と言うときの意味を明確にすることをお勧めします。おそらく、最初に演算子のオーバーロードではなく通常のメソッドとして表現すると、質問が明確になる場合があります。
確かにそれはできます。独自の 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;
}
実際、ライブラリまたはコードがオーバーロードを提供し、それが機能する場合は、それを行うことができ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 */
}
ピュアを使用する際の問題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.Iostream
ストリームを使用してデータを移動する必要はありません。これを行うために、独自のクラスを作成できます。これは例を示しています。明らかに、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;
}