I'm writing in Microsoft Visual C++ and I'd like my program to either read from standard input or a file using the istream_iterator
. Googling the internets hasn't shown how simple I think it must be. So for example, I can write this pretty easily and read from standard input:
#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());
}
Or I can write this and read from a file:
#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());
}
But how do I combine these two so that a simple (argc == 2)
check lets me initialize my input stream iterator with either a file stream or stdin and go on about my merry way?
You can assign to the iterator after constructing it:
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);
}
}
At first glance, the simplest solution would be to use the ternary operator ?:
like this:
istream_iterator<string> my_it( (argc == 2) ? ifstream(argv[1]) : cin );
However, that won't quite work because it constructs a temporary ifstream
object, which will be destroyed at the end of the statement. So you need a way of conditionally creating an ifstream
, and conditionally destroying it after the for
loop. std::auto_ptr<>
fits the bill. Thus:
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());
A different, probably cleaner solution would be to move the iteration to a separate function that takes istream&
.
I've seen this problem before online, covered by one of the C++ greats. Unfortunately, I don't remember exactly where, or by whom! I think it was on DDJ, maybe Sutter or Alexandrescu?
This small snippet will give you an istream input
that can be either a file or std::cin.
std::ifstream filestream;
if ( use_file )
filestream.open( ... );
std::istream &input = use_file ? filestream : std::cin;
You may now use input
without worrying which source the input is coming from.
Do you mean something like this: (using pointers)
#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;
}
I haven't tested this, though. Is that sort of what you're after?