2016-06-01 3 views
7

Я пытаюсь написать свою программу, чтобы она могла обрабатывать либо StdIn, либо файл, указанный в командной строке.Инициализация ссылки на istream

Я делаю это, пытаясь инициализировать ссылку на istream или ссылаться на cin или ifstream, используя условное обозначение.

(подобные методы описаны here и here)

Но когда я пытаюсь с ifstream, я, кажется, получаю сообщение об ошибке, что basic_istream ход-конструктор объявлен 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 

Можно ли это сделать таким образом? Есть ли хорошая альтернатива, которую я пропускаю?

+0

'ifstream (арг [1])' создает временный. Вы не можете привязывать к нему неконстантную ссылку. И ваш первый пример (reftofile) определяет функцию, а не объект. – SergeyA

+0

Я добавил 'const', но это не меняет существенную проблему. – abelenky

+0

Да, я объясню в ответе. – SergeyA

ответ

3

Проблема с кодом заключается в следующем:

Ваша левая сторона тройном оператора является временным (Rvalue). Однако ваша правая сторона является lvalue (cin является lvalue). В результате компилятор пытается создать временное из cin и сбой из-за невозможности использования конструктора копирования.

Что касается sultions - вы можете просто заменить rdbuf() из cin с rdbuf() вашего файла и использовать cin всюду.


Вот окончательное решение О.П. придумал:

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 
+0

Простите редактирование, но я хотел показать свое окончательное решение на основе вашего ответа без отдельного сообщения. – abelenky

+2

@abelenky - отредактируйте прощение :) Одна вещь, хотя - вам лучше заменить rdbuf назад перед закрытием файла. – SergeyA

+0

Хорошо, теперь мой ответ опущен. Можете ли почтенный спутник подавать аргументы? – SergeyA

1

Это пахнет как XY problem, потому что вы не нужно тройная условное или ссылочный здесь.

В качестве условного обозначения многие программы используют - для обозначения stdin, а не для пропуска имени файла. Это один из возможных путей. В аналогичной мысли я использовал Boost.ProgramOptions или getopt вместо ручного разбора командной строки. Это косвенно решит вашу проблему XY, так как это сделает функцию FileIsProvided() избыточной, и вы будете получать свои варианты с помощью других методов, кроме использования argv[1].

Если у вас есть C++ 11, есть умные указатели или std::reference_wrapper, что позволяет вам «переустанавливать» ссылки.

Как антимотиватор, считайте, что классы, такие как ostream_joiner, содержат указатель на свои внутренние объекты потока, не ссылку. Кроме того, я сомневаюсь, что вам нравится думать о том, чтобы иметь дело с оборванными ссылками из безобидного кода.

В противном случае ...

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

Я не намерен импортировать библиотеки Boost, когда вся завершенная программа имеет длину всего 70 строк и скомпилирована до 20K. В более крупной программе это может быть целесообразным. Но когда все это сразу подходит к экрану, я не против самостоятельно управлять несколькими предметами. – abelenky

Смежные вопросы