Я привык писать небольшие инструменты командной строки, которые принимают либо имя файла, либо читаются с std::cin
, поэтому я довольно долго использовал этот шаблон:
int main(int argc, char* argv[])
{
std::string filename;
// args processing ...
std::ifstream ifs;
if(!filename.empty())
ifs.open(filename);
std::istream& is = ifs.is_open() ? ifs : std::cin;
std::string line;
while(std::getline(is, line))
{
// process line...
}
return 0;
}
После прочтения вопроса о переполнении стека, я попытался изменить свой обычный шаблон в соответствии с необходимостью читать либо из файла, либо из std::istringstream
. К моему удивлению, он не будет компилироваться и дает эту ошибку:
temp.cpp:164:47: error: invalid initialization of non-const reference of type ‘std::istream& {aka std::basic_istream<char>&}’ from an rvalue of type ‘void*’ std::istream& is = ifs.is_open() ? ifs : iss; // won't compile
Мне кажется, что он пытается преобразовать объект std::istringstream
(iss
) в boolean и получить его operator void*()
.
int main(int argc, char* argv[])
{
std::string filename;
std::string data;
// args processing ...
std::ifstream ifs;
std::istringstream iss;
if(!filename.empty())
ifs.open(filename);
std::istream& is = ifs.is_open() ? ifs : iss; // won't compile
std::string line;
while(std::getline(is, line))
{
// process line...
}
return 0;
}
-
Почему он обрабатывает
std::istringstream
иначе, чемstd::cin
иstd::ifstream
? Все они происходят отstd::istream
.Затем я вспомнил, что преобразовал свой шаблон, чтобы разместить три возможности: чтение из файла, строки или
std::cin
. И я помню, что работал (хотя и довольно неуклюжий). Поэтому, применяя тройное решение этой проблемы, я придумал выдумку, которая полностью работает:int main(int argc, char* argv[]) { std::string filename; std::string data; // args processing ... std::ifstream ifs; std::istringstream iss; if(!filename.empty()) ifs.open(filename); std::istream& is = ifs.is_open() ? ifs : true ? iss : std::cin; // fudge works std::string line; while(std::getline(is, line)) { // process line... } return 0; }
-
Почему эта выдумка работает? Является ли GCC нарушением каких-либо правил о том, как тернарный оператор (
?:
) разрешает его типы? Или я что-то упускаю?