質問
ANSI C ++では、coutストリームを変数名に割り当てるにはどうすればよいですか?私がやりたいのは、ユーザーが出力ファイル名を指定した場合、そこに出力を送信し、そうでない場合は画面に送信します。次のようなものです:
ofstream outFile;
if (outFileRequested)
outFile.open("foo.txt", ios::out);
else
outFile = cout; // Will not compile because outFile does not have an
// assignment operator
outFile << "whatever" << endl;
これをマクロ関数としても実行しようとしました:
#define OUTPUT outFileRequested?outFile:cout
OUTPUT << "whatever" << endl;
しかし、コンパイラエラーも発生しました。
IF-THENブロックをすべての出力に使用できると思っていましたが、できればそれを避けたいと思います。何か案は?
解決
参照を使用します。 std :: cout
はであるため、参照は
なので、最小公分母を使用する必要があります。 std :: ofstream
ではなく、 std :: ostream
型でなければならないことに注意してください。 std :: ostream
std::ofstream realOutFile;
if(outFileRequested)
realOutFile.open("foo.txt", std::ios::out);
std::ostream & outFile = (outFileRequested ? realOutFile : std::cout);
他のヒント
あなたのプログラムは標準のUNIXツールのように動作し、ファイルが与えられないと標準出力に書き込み、ファイルが与えられるとそのファイルに書き込むと仮定します。 cout
をリダイレクトして、別のストリームバッファに書き込むことができます。リダイレクトが有効である限り、coutに書き込まれたものはすべて、指定した宛先に透過的に書き込まれます。リダイレクトオブジェクトがスコープ外に出ると、元のストリームが置かれ、出力が再び画面に書き込まれます。
struct CoutRedirect {
std::streambuf * old;
CoutRedirect():old(0) {
// empty
}
~CoutRedirect() {
if(old != 0) {
std::cout.rdbuf(old);
}
}
void redirect(std::streambuf * to) {
old = std::cout.rdbuf(to);
}
}
int main() {
std::filebuf file;
CoutRedirect pipe;
if(outFileRequested) {
file.open("foo.txt", std::ios_base::out);
pipe.redirect(&file);
}
}
今では、パイプがメインで生きている限り、coutはファイルにリダイレクトされます。もっと「本番対応」にすることができます。コピーする準備ができていないため、コピー不可にします。コピーが範囲外になると、元のストリームが既に復元されます。
ここでこれを行う方法の非常に詳細な説明を見つけることができます: http://groups.google.com/group/ comp.lang.c ++ / msg / 1d941c0f26ea0d81?pli = 1
うまくいけば、誰かがスタックオーバーフローがポイントを獲得するためにこれをもっと明確に書くでしょう...
Adam Rosenfield の追跡に従いますが、三項演算子とコンマ演算子を使用して参照初期化の問題を修正します:
bool outFileRequested = false;
std::ofstream realOutFile;
std::ostream & outFile = outFileRequested
? realOutFile.open("foo.txt", std::ios::out), realOutFile
: std::cout;
outFile << "some witty remark";
(VSでテスト済み)
アダムは正しい軌道に乗っていると思いますが、参照を割り当てることはできないと思います-代わりにポインタを使用する必要があります:
std::ofstream realOutFile;
std::ostream * poutFile;
if(outFileRequested)
{
realOutFile.open("foo.txt", std::ios::out);
poutFile = &realOutFile;
}
else
poutFile = &std::cout;
その後、ポインタの値になるように参照を定義できますが、グローバルではありません
std::ostream & outFile = *poutFile;
ストリームの型の変数にcoutを割り当てることができるかどうかわかりません。 coutはostream型のオブジェクトであり(cinはistream型です)、一方が他方から継承するかどうかはわかりません。そのため、ファイルが指定されているかどうかを確認し、適切なストリームタイプを作成することをお勧めします。
これを取得するには約2時間かかりました。基本的に、テストスイートを実行する外部クラスがあります。テストを実行するデリゲートを送信するため、出力にアクセスするには出力ストリームを送信する必要があります。テストごとに異なるストリームを実行できたと思います。とにかく、後で使用するためにofstreamを渡したいと思いました。
// Main code to create Test Suite Object
ofstream debugFile("debug.txt");
TestSuiteObject* myTestSuite = new TestSuiteObject(&debugFile);
// Test Suite Object
class TestSuiteObject: public Test::Suite
{
public:
TestSuiteObject(std::ofstream* debug) : m_debug(*debug)
{
m_debug << "some witty remark" << std::endl;
TEST_ADD(TestSuiteObject::test1);
TEST_ADD(TestSuiteObject::test2);
TEST_ADD(TestSuiteObject::test3);
}
void test1();
void test2();
void test3();
private:
std::ofstream& m_debug;
};