2009-01-09 9 views
13

En ANSI C++, ¿cómo puedo asignar la secuencia cout a un nombre de variable? Lo que quiero hacer es que, si el usuario ha especificado un nombre de archivo de salida, envíe la salida allí, de lo contrario, envíela a la pantalla. Así que algo como:Asignación de cout a un nombre de variable

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; 

He intentado hacer esto como una función macro, así:

#define OUTPUT outFileRequested?outFile:cout 

OUTPUT << "whatever" << endl; 

Pero eso me dio un error de compilación también.

Supuse que podría usar un bloque IF-THEN para cada salida, pero me gustaría evitar eso si pudiera. ¿Algunas ideas?

Respuesta

34

utilizar una referencia. Tenga en cuenta que la referencia debe ser de tipo std::ostream, no std::ofstream, ya que std::cout es std::ostream, por lo que debe utilizar el mínimo común denominador.

std::ofstream realOutFile; 

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

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

Esa es una solución muy elegante. ¡Gracias! – user12576

0

creo que Adán en el camino correcto, pero no creo que se puede asignar referencias - es necesario utilizar un puntero en su lugar:

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

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

usted podría entonces definir una referencia que es el valor del puntero, pero no sería mundial

std::ostream & outFile = *poutFile; 
+0

Siempre debería preferir usar referencias sobre punteros. Y se puede hacer con referencias. Vea el código fijo arriba. –

+1

Claro, simplemente no puede usar una variable global con una referencia b/c. No podrá inicializar al valor correcto. – KenE

0

no estoy seguro de que se puede asignar cout a una variable de tipo ofstream. cout es un objeto de tipo ostream (mientras que cin es de tipo istream) y no estoy seguro de que uno herede del otro. Por lo tanto, tal vez sea mejor abordar algo para ver si se proporcionó/​​existe un archivo y crear el tipo de flujo apropiado.

1

Siguiendo pistas Adam Rosenfield 's, pero solucionar el problema de inicialización de referencia con los operadores ternarios y comas:

bool outFileRequested = false; 

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

outFile << "some witty remark"; 

(Probado en VS)

8

Asumo el programa se comporta como herramientas estándar de Unix , que cuando no se da un archivo escribirá en la salida estándar, y cuando se le dé un archivo escribirá en ese archivo. Puede redirigir cout para escribir en otro buffer de transmisión. Mientras su redireccionamiento esté activo, todo lo escrito para cout se escribe de forma transparente en el destino que usted designó. Una vez que el objeto de redirección se sale del ámbito, la corriente original se pone y la salida será escribir en la pantalla de nuevo:

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

Ahora, cout se redirige al archivo siempre y cuando el tubo está vivo en principal. Puede hacerlo más "listo para producción" al hacer que no se pueda copiar, porque no está listo para ser copiado: si la copia sale del alcance, ya restauraría la transmisión original.

+0

Creo que esta estructura debería ser un singleton. –

+2

Hosam, a propósito no es un singleton, para permitir temporalmente cambiar el destino de cout, un singleton cambiaría cout para siempre. incluso si no quiere cambiarlo solo temporalmente, si puede hacer algo sin un singleton, debería hacerlo sin él. Aquí, creo que se puede hacer claramente sin –

0

Esto tomó alrededor de dos horas en llegar. Básicamente, tengo una clase externa ejecutando un conjunto de pruebas. Envié un delegado para ejecutar las pruebas, por lo que para tener acceso a la salida necesito enviar una secuencia de salida.Supongo que podría haber hecho una secuencia diferente por prueba. De todos modos, quería pasar en el flujo para ser utilizado más tarde.

// 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; 
}; 
+0

¿Estás seguro de que has puesto esto en el lugar correcto? No parece responder a la pregunta ... – dmckee

Cuestiones relacionadas