Подтвердить что ты не робот

Назначение 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 для каждого выхода, но я хотел бы избежать этого, если бы мог. Есть идеи?

4b9b3361

Ответ 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 перенаправляется в файл до тех пор, пока канал остается в основном. Вы можете сделать его более "готовым к производству", сделав его не скопированным, потому что он не готов к копированию: если копия выходит за рамки, она уже восстановит исходный поток.

Ответ 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;
};