2009-12-16 15 views
4

J'écris dans Microsoft Visual C++ et j'aimerais que mon programme lise à partir de l'entrée standard ou un fichier en utilisant le istream_iterator. Googler les internets n'a pas montré à quel point je pense qu'il doit être simple. Ainsi, par exemple, je peux écrire ce assez facilement et lire l'entrée standard:Utilisation de istream_iterator et lecture à partir de l'entrée ou du fichier standard

#include <iostream> 
#include <string> 
#include <iterator> 

using namespace std; 

int main() 
{ 
    istream_iterator<string> my_it(cin); 
    for (; my_it != istream_iterator<string>(); my_it++) 
     printf("%s\n", (*my_it).c_str()); 
} 

Ou je peux écrire cela et lire un fichier:

#include <iostream> 
#include <string> 
#include <iterator> 
#include <fstream> 

using namespace std; 

int main(int argc, char** argv) 
{ 
    ifstream file(argv[1]); 
    istream_iterator<string> my_it(file); 
    for (; my_it != istream_iterator<string>(); my_it++) 
     printf("%s\n", (*my_it).c_str()); 
} 

Mais comment puis-je combiner ces deux pour que une simple vérification (argc == 2) me permet d'initialiser mon itérateur de flux d'entrée avec un flux de fichier ou un fichier stdin et de continuer mon chemin joyeux?

Répondre

10

Vous pouvez attribuer à la iterator après le construire:

int main(int argc, char** argv) 
{ 
    ifstream file; 
    istream_iterator<string> my_it; 

    if(argc == 2) { 
     file.open(argv[1]); 
     my_it = istream_iterator<string>(file); 
    } else { 
     my_it = istream_iterator<string>(cin); 
    } 
} 
1

Ce petit fragment vous donnera un istream input qui peut être un fichier ou std :: cin.

std::ifstream filestream; 
if (use_file) 
    filestream.open(...); 
std::istream &input = use_file ? filestream : std::cin; 

Vous pouvez maintenant utiliser input sans se soucier quelle source l'entrée vient.

+0

Ceci tente de lier une valeur r à une référence non-const, et est illégale en C++. –

+0

@Alex: Si un opérande peut être implicitement converti en une référence à l'autre type, le résultat est un lvalue. http://www.open-std.org/jtc1/sc22/wg21/docs/wp/html/nov97-2/expr.html#expr.cond –

+0

Vous semblez avoir raison - VC 2008 compile cela sans problème . On dirait un bug VC 2005. –

0

Voulez-vous dire quelque chose comme ceci: (en utilisant des pointeurs)

#include <iostream> 
#include <string> 
#include <iterator> 
#include <fstream> 

using namespace std; 

int main(int argc, char** argv) 
{ 
    istream_iterator<string>* my_it = NULL; 
    if (argc == 2) 
    { 
     ifstream file(argv[1]); 
     my_it = new istream_iterator<string>(file); 
    } 
    else 
    { 
     my_it = new istream_iterator<string>(cin); 
    } 

    ... 

    delete my_it; 
} 

Je n'ai pas testé, cependant. Est-ce que c'est ce que vous cherchez?

1

À première vue, la solution la plus simple serait d'utiliser l'opérateur ternaire ?: comme ceci:

istream_iterator<string> my_it((argc == 2) ? ifstream(argv[1]) : cin); 

Cependant, qui a gagné Ne fonctionne pas tout à fait car il construit un objet temporaire ifstream, qui sera détruit à la fin de la déclaration. Vous avez donc besoin d'un moyen de créer conditionnellement un ifstream et de le détruire conditionnellement après la boucle for. std::auto_ptr<> correspond à la facture. Ainsi:

auto_ptr<ifstream> file((argc == 2) ? new ifstream(argv[1]) : NULL); 
istream_iterator<string> my_it((argc == 2) : *file : cin); 
for (; my_it != istream_iterator<string>(); my_it++) 
    printf("%s\n", (*my_it).c_str()); 

Une autre solution probablement plus propre serait de déplacer l'itération à une fonction distincte qui prend istream&.

J'ai déjà vu ce problème avant en ligne, couvert par l'un des plus grands de C++. Malheureusement, je ne me souviens pas exactement où, ni par qui! Je pense que c'était sur DDJ, peut-être Sutter ou Alexandrescu?

+0

Cela tente également de lier un rvalue à une référence non-const. VC++ dit: 'Une référence non-const peut seulement être liée à une lvalue' –