Initializing a link to istream

I am trying to write my program so that it can process either StdIn or the file specified on the command line.

I am doing this by trying to initialize a link to istream or reference a cin or ifstream using a conditional expression.

(similar methods are described here and here )

But when I try with ifstream , I seem to get an error message that is declared by the move_istream protected constructor.

 istream& refToCIN ( cin ); // This is OK const istream& refToFile = ifstream(args[1]); // This is OK const istream& inStream ( FileIsProvided()? ifstream(args[1]) : cin ); // This causes error: // std::basic_istream<char,std::char_traits<char>>::basic_istream' : // cannot access protected member declared in class std::basic_istream<char,std::char_traits<char>> ProcessStream(inStream); // This could either be a file or cin 

Can this be done in this way? Is there a good alternative I'm missing out on?

+7
c ++ reference
source share
2 answers

The problem with your code is this:

Your left side of the ternary operator is temporary (rvalue). However, your right side is an lvalue ( cin is an lvalue). As a result, the compiler tries to create a temporary exit from cin and fails due to the inability to create a copy constructor.

As for the sultans - you can just replace rdbuf() cin with rdbuf() your file and use cin everywhere.


Here the final OP solution came up with:

 ifstream file; std::streambuf* old_cin_buf = cin.rdbuf(); // Store the old value if (FileIsProvided()) { file.open(args[1]); old_cin_buf = cin.rdbuf(file.rdbuf()); // Replace the ReadBuffer on cin. // Store the previous value as well. } // Use cin for all operations now. It will either use the File or StdIn as appropriate. ... // Restore the original value, in case it was changed by using a file. cin.rdbuf(old_cin_buf); // This is better be done before file object here goes out of scope 
+3
source share

This smells like an XY problem, because here you don't need a triple conditional link or link.

As a rule, many programs use - to indicate stdin , and not to refuse the file name. This is one of the possible ways. In a similar thought, I used Boost.ProgramOptions or getopt instead of manually parsing the command line. This will indirectly solve your XY problem, as it will make the FileIsProvided() function redundant, and you will get your parameters using other methods than directly using argv[1] .

If you have C ++ 11, there are smart pointers or std::reference_wrapper , which allows you to "reset" the links.

As an anti-motivator, consider classes like ostream_joiner to keep a pointer to their internal stream objects, not a link. Also, I doubt that you like to think about dealing with dangling links from harmless looking code.

Otherwise...

 if (FileIsProvided()) { std::ifstream ifs(argv[1]); if (ifs) { ProcessStream(ifs); } } else { ProcessStream(std::cin); } 
+1
source share

All Articles