Присвоение cout имени переменной
Вопрос
Как я могу назначить поток cout в имени переменной в ANSI C ++? Я хочу, чтобы, если пользователь указал имя выходного файла, я отправил туда вывод, иначе отправлю его на экран. Так что-то вроде:
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 :: ostream
, а не std :: ofstream
, поскольку std :: cout
является 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 перенаправляется в файл, пока канал работает в main. Вы можете сделать его более «готовым к производству» сделав его не подлежащим копированию, потому что он не готов к копированию: если копия выйдет из области видимости, она уже восстановит исходный поток.
Вы можете найти очень подробное объяснение того, как это сделать, здесь: http://groups.google.com/group/ comp.lang.c ++ / сообщ / 1d941c0f26ea0d81? пли = 1
Надеюсь, кто-то напишет это более четко для переполнения стека, чтобы получить очки ...
Следуя трекам Адама Розенфилда , но исправляя проблему инициализации ссылок с помощью троичных операторов и операторов запятой:
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 переменной типа ofstream. cout - это объект типа ostream (тогда как cin имеет тип istream), и я не уверен, что одно наследуется от другого. Так что, возможно, что-то, проверяющее, был ли файл задан / существует, и создание подходящего типа потока было бы лучшим подходом.
Это заняло около двух часов. По сути, у меня есть внешний класс, запускающий набор тестов. Я отправляю делегата для запуска тестов, поэтому для того, чтобы получить доступ к выводу, мне нужно отправить в выходной поток. Я думаю, я мог бы сделать другой поток за тест. В любом случае, я хотел передать в 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;
};