2009-01-09 16 views
13

En C++ ANSI, comment puis-je affecter le flux cout à un nom de variable? Qu'est-ce que je veux faire est, si l'utilisateur a spécifié un nom de fichier de sortie, j'envoie la sortie là, sinon, l'envoyer à l'écran. Donc, quelque chose comme:Affectation de cout à un nom 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; 

J'ai essayé de faire cela en fonction Macro ainsi:

#define OUTPUT outFileRequested?outFile:cout 

OUTPUT << "whatever" << endl; 

Mais cela m'a donné une erreur de compilation ainsi.

Je supposais que je pouvais soit utiliser un bloc IF-THEN pour chaque sortie, mais je voudrais éviter cela si je le pouvais. Des idées?

Répondre

34

Utiliser une référence. Notez que la référence doit être de type std::ostream, et non std::ofstream, puisque std::cout est un std::ostream, vous devez donc utiliser le plus petit dénominateur commun.

std::ofstream realOutFile; 

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

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

C'est une solution très élégante. Merci! – user12576

0

Je pense que Adam sur la bonne voie, mais je ne pense pas que vous pouvez attribuer des références - vous devez utiliser un pointeur à la place:

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

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

vous pouvez alors définir une référence pour être la valeur du pointeur, mais il ne serait pas globale

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

Préférez toujours utiliser des références sur des pointeurs. Et cela peut être fait avec des références. Voir le code fixe ci-dessus. –

+1

Bien sûr, vous ne pouvez pas utiliser une variable globale avec une référence b/c, vous ne serez pas en mesure d'initialiser à la bonne valeur. – KenE

0

Je ne suis pas sûr que vous pouvez assigner à une variable cout de type ofstream. cout est un objet de type ostream (alors que cin est de type istream) et je ne suis pas sûr que l'un hérite de l'autre. Donc, peut-être que quelque chose de vérifier pour voir si un fichier a été donné/existe et créer le type de flux approprié serait une meilleure approche.

1

Après Adam Rosenfield pistes de, mais régler le problème d'initialisation de référence avec des opérateurs ternaires et la virgule:

bool outFileRequested = false; 

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

outFile << "some witty remark"; 

(Testé VS)

8

Je suppose que votre programme se comporte comme des outils standard unix , que lorsqu'il n'est pas donné un fichier écrira à la sortie standard, et quand donné un fichier écrira dans ce fichier. Vous pouvez rediriger cout pour écrire dans un autre tampon de flux. Tant que votre redirection est active, tout ce qui est écrit dans Cout est écrit de manière transparente dans la destination que vous avez désignée. Une fois l'objet de redirection est hors de portée, le flux original est mis et sortie écrire à nouveau l'écran:

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

Maintenant, est Cout redirigé vers le fichier tant que le tuyau est vivant dans le principal. Vous pouvez le rendre plus "prêt à la production" en le rendant non-copiable, car il n'est pas prêt à être copié: Si la copie est hors de portée, elle restaure déjà le flux original.

+0

Je pense que cette structure devrait être un singleton. –

+2

Hosam, c'est délibérément pas un singleton, pour permettre de changer temporairement la destination de cout, un singleton changerait cout pour toujours. Même si vous ne voulez pas le changer seulement temporairement, si vous pouvez faire quelque chose sans un singleton, vous devriez le faire sans. Ici, je pense que cela peut clairement se faire sans –

0

Cela a pris environ deux heures à obtenir. Fondamentalement, j'ai une classe externe exécutant une suite de tests. J'envoie un délégué pour exécuter les tests, donc pour avoir accès à la sortie j'ai besoin d'envoyer un flux de sortie.Je suppose que j'aurais pu faire un flux différent par test. De toute façon, je voulais passer dans l'ofstream pour être utilisé plus tard.

// 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

Etes-vous sûr que vous avez mis cela au bon endroit? Il ne semble pas être sensible à la question ... – dmckee