Вопрос

Как я могу назначить поток 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;
};
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top