Pergunta

Na ANSI C ++, como posso atribuir o fluxo de cout a um nome de variável? O que eu quero fazer é que, se o usuário especificou um nome de arquivo de saída, envio a saída para lá, caso contrário, envie -o para a tela. Então, algo como:

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;

Eu tentei fazer isso como uma função macro também:

#define OUTPUT outFileRequested?outFile:cout

OUTPUT << "whatever" << endl;

Mas isso me deu um erro do compilador também.

Eu supunha que poderia usar um bloco IF-Then para cada saída, mas gostaria de evitar isso, se pudesse. Alguma ideia?

Foi útil?

Solução

Use uma referência. Observe que a referência deve ser do tipo std::ostream, não std::ofstream, desde std::cout é um std::ostream, então você deve usar o denominador menos comum.

std::ofstream realOutFile;

if(outFileRequested)
    realOutFile.open("foo.txt", std::ios::out);

std::ostream & outFile = (outFileRequested ? realOutFile : std::cout);

Outras dicas

Suponho que seu programa se comporta como as ferramentas do Unix Standard, que, quando não receber, um arquivo gravará na saída padrão e, quando receber um arquivo, gravará nesse arquivo. Você pode redirecionar cout Para escrever em outro buffer de fluxo. Enquanto seu redirecionamento estiver vivo, tudo escrito para Cout é escrito de forma transparente para o destino que você designou. Depois que o objeto de redirecionamento sair do escopo, o fluxo original é colocado e a saída será gravada na tela novamente:

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);
    }
}

Agora, o Cout é redirecionado para o arquivo, desde que o tubo esteja vivo em Main. Você pode torná-lo mais "produção pronta" tornando-a não copia, porque não está pronta para ser copiada: se a cópia sair do escopo, ela já restaurará o fluxo original.

Você pode encontrar uma explicação muito detalhada de como fazer isso aqui:http://groups.google.com/group/comp.lang.c++/msg/1d941c0f26ea0d81?pli=1

Espero que alguém escreva isso com mais clareza para o Stack Overflow para levar os pontos ...

Seguindo Adam RosenfieldAs faixas, mas corrigindo o problema de inicialização de referência com os operadores ternários e de vírgula:

bool outFileRequested = false;

std::ofstream realOutFile;
std::ostream & outFile = outFileRequested
    ? realOutFile.open("foo.txt", std::ios::out), realOutFile
    : std::cout;

outFile << "some witty remark";

(Testado em vs)

Eu acho que Adam está no caminho certo, mas acho que você não pode atribuir referências - você precisa usar um ponteiro:

std::ofstream realOutFile;
std::ostream * poutFile;

if(outFileRequested)
{
    realOutFile.open("foo.txt", std::ios::out);
    poutFile = &realOutFile;
}
else
    poutFile = &std::cout;

Você poderia então definir uma referência como o valor do ponteiro, mas não seria global

std::ostream & outFile = *poutFile;

Não tenho certeza se você pode atribuir o cout a uma variável de tipo de stream. O Cout é um objeto do tipo Ostream (enquanto o NIN é do tipo istream) e não tenho certeza de que um herda do outro. Então, talvez algo checando para ver se um arquivo foi dado/existe e a criação do tipo de fluxo apropriado seria uma abordagem melhor.

Isso levou cerca de duas horas para conseguir. Basicamente, eu tenho uma classe externa executando uma suíte de teste. Envio um delegado para executar os testes; portanto, para ter acesso à saída, preciso enviar um fluxo de saída. Acho que poderia ter feito um fluxo diferente por teste. De qualquer forma, eu queria passar no Ofstream para ser usado posteriormente.

// 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;
};
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top