Initializing reference to istream

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

I'm doing this by trying to initialize a reference to an istream to either refer to cin or an ifstream , using a conditional.

(similar techniques are described here and here)

But when I try with ifstream , I seem to get an error that the basic_istream move-constructor is declared protected .

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 reasonably done this way? Is there a good alternative I'm overlooking?


The problem with your code is following:

Your left-hand side of the ternary operator is a temporary (rvalue). However, your right hand-side is an lvalue ( cin is an lvalue). As a result, compiler is trying to create a temporary out of cin , and fails because of copy constructor being not available.

As for the sultions - you can simply replace rdbuf() of cin with rdbuf() of your file, and use cin everywhere.


Here's the ultimate solution OP 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

This smells like an XY problem because you don't need a ternary conditional or reference here.

As a matter of convention, many programs use - to denote stdin rather than omitting a filename. That's one possible avenue. On a similar line of thought, I would use Boost.ProgramOptions or getopt instead of manually parsing the command line. This will indirectly solve your XY problem as it'll make the FileIsProvided() function redundant and you'll be getting your options via other methods than using argv[1] directly.

If you have C++11, there's smart pointers or std::reference_wrapper , which allows you to "reseat" references.

As a anti-motivator, consider that classes like ostream_joiner keep a pointer to their internal stream objects, not a reference. Besides, I doubt that you enjoy the thought of having to deal with dangling references from innocuous looking code.

Otherwise...

if (FileIsProvided())
{
    std::ifstream ifs(argv[1]);
    if (ifs)
    {
        ProcessStream(ifs);
    }
} else {
    ProcessStream(std::cin);
}
链接地址: http://www.djcxy.com/p/91940.html

上一篇: 顶点着色器中的变换只适用于后期

下一篇: 初始化对istream的引用