MANIP(3CC4)

名前
manip - 入出力ストリーム用マニピュレータ

形式

#include <iostream.h>
#include <iomanip.h>

#define IOMANIPdeclare(typ) 以下の定義に展開 ...

class SMANIP(typ) {
public:
	SMANIP(typ)(ios& (*)(ios&, typ), typ);
	friend istream& operator>>(istream&, SMANIP(typ)&);
	friend ostream& operator<<(ostream&, SMANIP(typ)&);
};
class SAPP(typ) {
public:
	SAPP(typ)(ios& (*)(ios&, typ));
	SMANIP(typ) operator()(typ);
};
class IMANIP(typ) {
public:
	IMANIP(typ)(istream& (*)(istream&, typ), typ);
	friend istream& operator>>(istream&, IMANIP(typ)&);
};
class IAPP(typ) {
public:
	IAPP(typ)(istream& (*)(istream&, typ));
	IMANIP(typ) operator()(typ);
};
class OMANIP(typ) {
public:
	OMANIP(typ)(ostream& (*)(ostream&, typ), typ);
	friend ostream& operator<<(ostream&, OMANIP(typ)&);
};
class OAPP(typ) {
public:
	OAPP(typ)(ostream& (*)(ostream&, typ));
	OMANIP(typ) operator()(typ);
};
class IOMANIP(typ) {
public:
	IOMANIP(typ)(iostream& (*)(iostream&, typ), typ);
	friend istream& operator>>(iostream&, IOMANIP(typ)&);
	friend ostream& operator<<(iostream&, IOMANIP(typ)&);
};
class IOAPP(typ) {
public:
	IOAPP(typ)(iostream& (*)(iostream&, typ));
	IOMANIP(typ) operator()(typ);
};

IOMANIPdeclare(int);
IOMANIPdeclare(long);

smanip_long	resetiosflags(long);
smanip_int 	setbase(int);
smanip_int	setfill(int);
smanip_long	setiosflags(long);
smanip_int	setprecision(int);
smanip_int	setw(int);

機能説明

「マニピュレータ」は外見上、ストリームに挿入されたオブジェクト、 またはストリームから抽出されたオブジェクトのように見えます。 しかし、その多くはストリームの状態を変更するだけです。 マニピュレータの実際の目的は、 挿入シーケンスや抽出シーケンスに組み込むことで関数呼び出しによって 行う操作を簡略化することにあります。 たとえば、次のようなコードがあるとします。
cout.width(8);
cout << val1 << " ";
cout.width(4);
cout << val2 << '\n';
cout.flush();
このコードは次のように変更できます :
cout << setw(8) << val1 <<   << setw(4) << val2 << endl;

ios(3CC4)、 istream(3CC4)、 ostream(3CC4) で説明されているような定義済みのマニピュレータがいくつかあります。 flush や上の例の endl などは、引数を持たない簡単なものです。 上の例の setw のようなマニピュレータは引数を持ちます。 ヘッダファイル <iomanip.h> には、 このようなマニピュレータのいくつかが定義されているほか、 プログラマが独自のマニピュレータを作成するのに必要な定義が含まれています。

論理上、マニピュレータはテンプレートとして定義されますが、 C++ 言語では、テンプレートが利用可能になる前に導入されました。 したがって、マニピュレータはテンプレートをシミュレートするマクロとして 定義されます。 マクロ IOMANIPdeclare(typ) は、 typ 型の引数を持つマニピュレータのすべての定義に展開されます。 マクロの性質上、型を指定するパラメタは 単純な型名 (識別子だけ) であることが必要です。 ヘッダには、 int 型および long 型の展開された定義が含まれています。

  パラメタを持たない

  マニピュレータ
引数を持たないマニピュレータは、 「ストリームへの参照」型の引数を 1 つ持つ関数で、 同じ型の値を返します。 ストリームには、 そのような関数をパラメタに持つ多重定義演算子があらかじめ定義されています。 マニピュレータは、 ストリーム引数で必要なすべての操作を行い、同じストリームを返します。 たとえば、マニピュレータ tab のコードは次のようになります。
ostream& tab(ostream& s)
{
	s << '\t';
	return s;
}
式 cout<<tab の中で、多重定義された演算子
ostream& operator<< (ostream& (*)(ostream&))
が選択され、マニピュレータ関数を呼び出します。 呼び出されたマニピュレータは、出力ストリーム (ostream) にタブ文字を挿入します。

  パラメタを持つ

  マニピュレータ

パラメタを持つマニピュレータは、2 つの部分から構成されます。
- 操作部 : ストリームと引数 typ から、そのストリームを返す関数。
- 適用部 : 操作部によって呼び出される関数で、 状態の変更や他の操作を適用します。
指定された型 typ に対し、 マクロ IOMANIPdeclare によってすべての部分が宣言されます。 これについて、以下で詳しく説明します。

以下の説明では、次の宣言を想定しています。
typ - 何らかの型名
n - int 型
l - long 型
s - ios 型
i - istream 型
o - ostream 型
io - iostream 型
f - ios& (*) (ios&) 型
if - istream& (*) (istream&) 型
of - ostream& (*) (ostream&) 型
iof - iostream& (*) (iostream&) 型
s << SMANIP(typ)(f, t)
s << SAPP(typ)(f)(t)
s >> SMANIP(typ)(f, t)
s >> SAPP(typ)(f)(t)
f(s,t) を返します。 ストリーム s は、他のストリーム型 ( i 、 o 、 io ) の いずれかになることがあります。

i >> IMANIP(typ)(if, t)
i >> IAPP(typ)(if)(t)
if(i,t) を返します。

o << OMANIP(typ)(of, t)
o << OAPP(typ)(of)(t)
of(o,t) を返します。

io << IOMANIP(typ)(iof, t)
io << IOAPP(typ)(iof)(t)
io >> IOMANIP(typ)(iof, t)
io >> IOAPP(typ)(iof)(t)
iof(io,t) を返します。

ヘッダ <iomanip.h> には、 int 型または long 型の引数 (上記の typ を持つマニピュレータの 定義が含まれています。 定義済みのマニピュレータはすべて、次のようにストリームの状態を変更するために 使用されます。

o << setw(n)
i >> setw(n)
ストリーム i または o のフィールド幅を n に設定します。 次の書式つき挿入または抽出では、 この幅が 0 に再設定されるので注意が必要です。

o << setfill(n)
i >> setfill(n)
ストリーム i または o のパディング文字を n に設定します。

o << setprecision(n)
i >> setprecision(n)
ストリーム i または o の 精度変数 (小数部の有効桁数) を n に設定します。

o << setiosflags(l)
i >> setiosflags(l)
ストリーム i または o の ios フラグのうち、 l でセットされているビットに対応するものをオンにします。

o << resetiosflags(l)
i >> resetiosflags(l)
ストリーム i または o の ios フラグのうち、 l でセットされているビットに対応するものをオフにします。

引数を持つマニピュレータを独自に作成するには、 まず「操作」関数を宣言した後、 「操作」関数と「適用」関数の両方を実装する必要があります。 マニピュレータが typ 型の引数を持つようにするには、 同じ型の引数を 1 つ持ち、 X manip_typ 型のオブジェクトを返す 「操作」関数を宣言する必要があります。 ここで、操作しようとするオブジェクトの型が ios、istream、 ostream、iostream である場合にはそれぞれ、 X を s、i、 o、io に置き換えてください。 また、 typ は実際の型名に置き換えます。 int 型または long 型の場合、 すべての宣言はすでに整えられています。 他の型の場合は、 「テンプレート」である IOMANIPdeclare ( typ ) を 呼び出す必要があります。

適用関数は操作関数からしか呼び出されないため、通常は静的にします。 適用関数は、操作対象のストリームの型への参照を返し、 同じ型を第 1 パラメタに持ち、 型 typ を第 2 パラメタに持つように定義してください。

例として、 setiosflags というマニピュレータを考えます。 このマニピュレータは ios 上で動作し、 long 型の引数を持つため、 smanip_long 型の値を返すように宣言されています。 このパラメタが ostream 上で動作し、 int 型のパラメタを持つのであれば、 omanip_int 型の値を返すように宣言されます。 したがって、このパラメタ (操作関数) は、 ヘッダで次のように宣言されています。
smanip_long setiosflags(long);

適用関数はユーザーコードから直接呼び出されることはないため、 ヘッダには宣言されません。 実装モジュールでは、 これらの関数のコードは次のようになっています。

// b に設定されているビットに従ってフラグ bitvector を設定
static ios& sios(ios& i, long b) // 非公開適用関数
{
	i.setf(b);
	return i;
}
smanip_long setiosflags(long b) // 公開操作関数
{
	return smanip_long(sios, b);
}

関連項目

ios.intro(3CC4)、 ios(3CC4)、 istream(3CC4)、 ostream(3CC4)、 『C++ ライブラリ・リファレンスマニュアル』の第 3 章「iostream ライブラリ」