出力する場合は、外部の(メンバ関数でない)関数でも記述できる。 しかし、入力する場合は(構築するわけだから)メンバ関数でないと 記述できないことがある。(あるいは、穴を開けることになる。)
だが、例えば、MFCのCArchiveに対してシリアライズを行いたい場合、 クラスにCArchiveを認識させなければいけないが、これは汎用性に欠ける。 (UNIXではMFCなど使えないから、UNIXには持っていけない。)
解決法としては3案ほど考えられる。
最もスマートなのは、メンバ関数テンプレートを用いる方法であろう。
template <class T> void Load(T& t){t >> m_i >> m_j;}という具合に。しかし、メンバ関数テンプレートは現在の所、 殆どのコンパイラでサポートされてない。よって、これはあきらめるしかない。
2番目の方法は、正統派のやり方である。ストリームのための抽象クラスを用意して
それをインターフェースにして行う方法である。(サンプル)
但し、この方法は、面倒くさいし、使いたいストリームが拡張されたときに、
直さなければいけない。(例えば、stringがistreamをサポートした場合など。)
3番目の方法は、ちょっと邪道かもしれない。構築用のメンバ関数を用意するのである。
これは、穴となるかもしれないので、公開したくないのだが、それもできない。
具体的には、
class AnyClass { ... void Load(int i,int j){m_i = i; m_j = j;} }; template <class T> T& operator>>(T& t,AnyClass& a) { int i,j; t >> i >> j; a.Load(i,j); }という感じになる。(operator<<の方は省略した。) この方法の方が、2番目よりも柔軟性があるのでこれがよいかもしれない。 これで、iostreamでもfstreamでもsstreamでもCArchiveでも使える。
t << m_i << ' ' << m_j; t >> m_i >> m_j;しかし、ストリームがCArchiveだとうまく行かない。そのときは、次のようにするとよい。
char c; t >> m_i >> c >> m_j;つまり、余分な文字をダミーの変数に入れてしまうのである。