Использование istream_iterator и чтение из стандартного ввода или файла - PullRequest
6 голосов
/ 16 декабря 2009

Я пишу в Microsoft Visual C ++, и я хотел бы, чтобы моя программа читала из стандартного ввода или из файла, используя istream_iterator. Поиск в интернете не показал, насколько простым я думаю, должно быть. Так, например, я могу довольно легко написать это и прочитать из стандартного ввода:

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

Или я могу написать это и прочитать из файла:

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

Но как мне объединить эти два, чтобы простая проверка (argc == 2) позволила мне инициализировать мой итератор входного потока либо с файловым потоком, либо с stdin и продолжить мой веселый путь?

Ответы [ 4 ]

12 голосов
/ 16 декабря 2009

Вы можете назначить итератору после его построения:

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 голос
/ 16 декабря 2009

На первый взгляд, самое простое решение - использовать троичный оператор ?:, например:

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

Однако, это не совсем работает, потому что он создает временный объект ifstream, который будет уничтожен в конце оператора. Таким образом, вам нужен способ условного создания ifstream и его условного уничтожения после цикла for. std::auto_ptr<> соответствует требованиям. Таким образом:

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

Другим, возможно, более чистым решением было бы перенести итерацию в отдельную функцию, которая принимает istream&.

Я видел эту проблему до онлайн, о которой рассказал один из великих разработчиков C ++. К сожалению, я точно не помню, где и кем! Я думаю, что это было на DDJ, может быть, Саттер или Александреску?

1 голос
/ 16 декабря 2009

Этот небольшой фрагмент даст вам поток input, который может быть файлом или std :: cin.

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

Теперь вы можете использовать input, не беспокоясь о том, из какого источника поступает вход.

0 голосов
/ 16 декабря 2009

Вы имеете в виду что-то вроде этого: (используя указатели)

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

Хотя я не проверял это. Это то, что вы ищете?

...