Инициализация ссылки на istream
Я пытаюсь написать свою программу, чтобы она могла обрабатывать либо StdIn, либо файл, указанный в командной строке.
Я делаю это, пытаясь инициализировать ссылку на istream
либо обратиться к cin
или ifstream
, используя условный.
(подобные методы описаны здесь и здесь)
но когда я пытаюсь с ifstream
, кажется, я получаю ошибку, что basic_istream move-конструктор объявлено 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
можно ли это разумно сделать таким образом? Есть ли хорошая альтернатива, которую я упускаю?
2 ответов
проблема с вашим кодом следующая:
ваша левая сторона тернарного оператора является временной (rvalue). Однако, правой стороны является lvalue (cin
является lvalue). В результате компилятор пытается создать временное из cin
и завершается ошибкой из-за недоступности конструктора копирования.
что касается sultions - вы можете просто заменить rdbuf()
cin с rdbuf()
файла, и использовать cin
повсюду.
вот окончательное решение OP придумал:
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
это пахнет как проблема по XY потому что ты не нужно троичное условное или ссылка здесь.
как вопрос конвенции, многие программы используют -
для обозначения stdin
вместо того, чтобы опустить имя файла. Это один из возможных путей. На аналогичной мысли я бы использовал Boost.ProgramOptions или getopt
вместо ручного разбора командной строки. Это косвенно решит вашу проблему XY, поскольку это сделает