iostream の便利さが理解できない

[戻る]
tib 2004/11/30(火) 22:23:13
C++を使うようになって何年も経ちますが、未だにまともに使った事がないのが
「iostream」です。

私がC++を囓った初日に、ものの本に「型の安全性からもprintf()ではなくiostreamを使
うようにしましょう」といったようなことを書いていたと記憶していますが、例えば

double dPI = 3.1415926535;
double dE  = 2.7182818284;

が与えられていたとして、

( 3.14159, 2.71828)

と標準出力に出力するのにも、これまで

printf( "(%8.5f,%8.5f)\n", dPI, dE );

で済んでいたものを

cout << "(";
cout.width( 8 );    cout.precision( 6 );    cout << dPI;
cout << ",";
cout.width( 8 );    cout.precision( 6 );    cout << dE;
cout << ")" << endl;

としなくてはならない、と知って「可読性を落とすにも程がある」と投げ出してしまった
のです。

こうまでしてiostreamを使うメリットってどこにあるのでしょう?
それとも実はもっとスッキリ書く方法があるのでしょうか。

επιστημη 2004/12/01(水) 07:40:26
#include <iostream>
#include <iomanip>

using namespace std;

int main() {
  double dPI = 3.1415926535;
  double dE  = 2.7182818284;

  cout << '(' << setprecision(6) 
       << setw(8) << dPI << ','
       << setw(8) << dE  << ')'
       << endl;
  return 0;
}

επιστημη [E-Mail] [HomePage] 2004/12/01(水) 11:02:30
> こうまでしてiostreamを使うメリットってどこにあるのでしょう?

ユーザ定義型に対しても operator << が定義できる。

complex<double> z(3.14, 2.78);
cout << z << endl;

とか。

PATIO 2004/12/01(水) 11:23:51
既にεπιστημηさんが書かれていますけれど、
処理子(setwとか、setprecisionとかがそうです)を使えば、
そう見づらくもないと思います。
可読性は結局慣れの問題もあるのでC++の書き方が見づらいとは言い切れないと思いますし、
printf( "(%8.5f,%8.5f)\n", dPI, dE );が可読性が高いと感じているのは
C言語にどっぷり浸かっていた所為だと思いますよ。
それにprintfを使っていたのでは、クラスのおいしい所が生きてきませんから。
(επιστημηさんのoperator <<が定義できるという話です。)

Kazuki 2004/12/01(水) 11:59:34
こういうのも便利ですよね。
void WriteToStream(std::ostream &os)
{
  os << "Hello world";
}

int main()
{
  WriteToStream(std::cout); //標準出力にも
  std::ostringstream oss;
  WriteToStream(oss); //文字列にも
  std::ofstream ofs("hogehoge.txt");
  WriteToStream(ofs); //ファイルにも
  ofs.close();
  
  return 0;
}

後は,標準C++ライブラリにはstreamをイテレータとして使えるように
してくれるものもありますしね。

monkey 2004/12/01(水) 12:00:31
任意のクラスに対してストリーム出力用の operator << の定義し、
ストリームクラスのクラス階層を組み合わせて使ったときに最もメリットを感じます。
つまり、あるクラスに対してストリーム出力用の operator << が適切に定義されていれ
ば、
標準出力だけでなく、ファイルや文字列ストリームへの出力も << 演算子でできるとい
うこと。
書式指定は << の定義の中で1回だけ書けば良い。

class X{...};

std::ostream& operator << ( std::ostream& os, const X& x )
{
    return os << ... ;
}

int main()
{
   X x;
   std::cout << x; // 標準出力へ出力

   std::ofstream fout( "file.txt" );
   fout << x; // ファイルへ出力

   std::ostringstream oss;
   oss << x; // 文字列ストリームへ出力
}

こじま 2004/12/01(水) 14:52:55
正直言って、あんまり便利でないですよね。。
iostreamの一番の問題点は、いわゆる「デザインとロジックの分離」ができないことか
な。
出力する書式をロジックで指定しないといけないのは結構つらいですよね。

型安全なprintfが欲しいということであれば、boost::formatとかになるんでしょうか。

tib 2004/12/02(木) 18:36:03
[[解決]]
私がC++初日に躓いてそのままにしていた問題に対し、様々なご意見ありがとうございます。

επιστημηさん:
私が最初に示した例よりはずっと見やすいですが、それでも私にはprintf()の方が見やす
いと感じてしまいます。
ユーザー定義型のoperator<<を定義できるというのがメリットとしてある事は解りました
が、複数パターンの出力方式が求められる場合に対応しづらくなりませんか?

PATIO さん:
ご指摘の通り、長年見慣れているからこそprintf()寄りになってしまうというのもあるで
しょう。確かに引数が多くなるとprintf()もフォーマット記述と引数の型が一致している
のか不安になりますし、保守性がいいとはとても言えませんね。

Kazukiさん、monkeyさん:
これまでの経験上あまりそういうパターンが殆どなかった(ファイルへの出力自体あまり
やらない)ので気付きませんでしたが、ファイルも文字列も同じように扱えるというのは
確かにメリットになりますね。

こじまさん:
boost::format !! これはいいですね。特に同じ意味のメッセージをいくつもの言語で
フォーマットしなくてはならない私には利用価値が高そうです。


皆さんのおかげで今まで避けていた領域に踏み込めそうです。ありがとうございました。

古いスレッドには追加発言できません。