Назначение cout для имени переменной
В ANSI С++, как я могу назначить поток 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 для каждого выхода, но я хотел бы избежать этого, если бы мог. Есть идеи?
Ответы
Ответ 1
Используйте ссылку. Обратите внимание, что ссылка должна быть типа 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);
Ответ 2
Я предполагаю, что ваша программа ведет себя как стандартные инструменты 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 перенаправляется в файл до тех пор, пока канал остается в основном. Вы можете сделать его более "готовым к производству", сделав его не скопированным, потому что он не готов к копированию: если копия выходит за рамки, она уже восстановит исходный поток.
Ответ 3
Вы можете найти очень подробное объяснение, как это сделать здесь:
http://groups.google.com/group/comp.lang.c++/msg/1d941c0f26ea0d81?pli=1
Надеюсь, кто-то напишет это более четко для, чтобы взять очки...
Ответ 4
Следуя трекам 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)
Ответ 5
Я думаю, что Адам на правильном пути, но я не думаю, что вы можете назначить ссылки - вместо этого вам нужно использовать указатель:
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;
Ответ 6
Я не уверен, что вы можете назначить cout переменной типаstream. cout является объектом типа ostream (тогда как cin имеет тип istream), и я не уверен, что он наследуется от другого. Таким образом, может быть, что-то проверяет, был ли файл указан/существует, и создание соответствующего типа потока было бы лучшим подходом.
Ответ 7
Это заняло около двух часов. В принципе, у меня есть внешний класс, в котором работает тестовый набор. Я отправляю делегата для запуска тестов, поэтому для доступа к выходу мне нужно отправить поток вывода. Наверное, я мог бы сделать другой поток за тест. В любом случае, я хотел перейти в поток, который будет использоваться позже.
// 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;
};