¿Por qué std :: istringstream parece resolverse de manera diferente a std :: ifstream en el operador ternario (? :)?

Estoy acostumbrado a escribir pequeñas herramientas de línea de comandos que toman un nombre de archivo o leenstd::cin, así que he estado usando este patrón durante bastante tiempo:

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;
}

Después de leer una pregunta sobre Stack Overflow, intenté modificar mi patrón habitual para adaptarlo a la necesidad de leerlo desde un archivo o desde unstd::istringstream. Para mi sorpresa, no se compilará y da este error:

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

Lo que me parece que está tratando de convertir elstd::istringstream objeto (iss) a un booleano y obtener suoperator 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;
}

¿Por qué está tratando?std::istringstream diferente destd::cin ystd::ifstream? Todos derivan destd::istream.

Entonces recordé haber convertido mi patrón para dar cabida a tres posibilidades, leer desde un archivo, cadena ostd::cin. Y recuerdo que funcionó (aunque es bastante torpe). Entonces, aplicando la solución triple a este problema, se me ocurrió un dulce de azúcar que funciona totalmente:

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;
}

¿Por qué funciona este dulce de azúcar? ¿GCC está infringiendo alguna regla sobre cómo el operador ternario (?:) resuelve sus tipos? ¿O me estoy perdiendo algo?

Respuestas a la pregunta(4)

Su respuesta a la pregunta