Pregunta

Quiero escribir una función que da salida a algo a un ostream que ha pasado, y volver la corriente, así:

std::ostream& MyPrint(int val, std::ostream* out) {
  *out << val;
  return *out;
}

int main(int argc, char** argv){
    std::cout << "Value: " << MyPrint(12, &std::cout) << std::endl;
    return 0;
}

Sería conveniente para imprimir el valor de esta manera y empotrar la llamada a función en la cadena operador de salida, como lo hice en main().

No funciona, sin embargo, e imprime la siguiente:

$ ./a.out
12Value: 0x6013a8

La salida deseada sería la siguiente:

Value: 12

¿Cómo puedo solucionar este problema? ¿Tengo que definir un operator<< lugar?

ACTUALIZACIÓN:. ha aclarado cuál sería la salida deseada

Update2: Algunas personas no entienden por qué me gustaría imprimir un número de esa manera, utilizando una función en lugar de imprimir directamente. Este es un ejemplo simplificado, y en realidad, la función imprime un objeto complejo en lugar de un int.

¿Fue útil?

Solución

No se puede arreglar la función. No hay nada en la especificación requiere un compilador para evaluar una llamada de función en una expresión en ningún orden en particular con respecto a algún operador no relacionada en la misma expresión. Así que sin cambiar el código de llamada, no se puede hacer después de evaluar MyPrint() std::cout << "Value: "

fin de izquierda a derecha es obligatorio para las expresiones que constan de múltiples operadores << consecutivos, por lo que va a funcionar. El punto de operador << volver la corriente es que cuando están encadenados operadores, el LHS de cada uno es suministrada por la evaluación del operador a su izquierda.

No se puede lograr lo mismo con las llamadas de función libres porque no tienen un LHS. MyPrint() devuelve un objeto igual a std::cout, y lo mismo ocurre std::cout << "Value: ", por lo que está haciendo con eficacia std::cout << std::cout, que es la impresión de que el valor hexadecimal.

Desde la salida deseada es:

Value: 12

lo "correcto" que hacer es de hecho para anular el operador <<. Con frecuencia, esto significa que necesita, ya sea que sea un amigo, o hacer esto:

class WhateverItIsYouReallyWantToPrint {
    public:
    void print(ostream &out) const {
        // do whatever
    }
};

ostream &operator<<(ostream &out, const WhateverItIsYouReallyWantToPrint &obj) {
    obj.print(out);
}

Si operator<< primordial para su clase no es el caso, por ejemplo, porque hay múltiples formatos que es posible que desee imprimir, y que desea escribir una función diferente para cada uno, entonces debe o bien renunciar a la idea de Secuencia de operadores y simplemente llamar a la función, o bien escribir varias clases que quitan el objeto como un parámetro de constructor, cada uno con diferentes sobrecargas de operadores.

Otros consejos

¿Quieres hacer una clase con MyPrint amigo << operador:

class MyPrint
{
public:
    MyPrint(int val) : val_(val) {}
    friend std::ostream& operator<<(std::ostream& os, const MyPrint& mp) 
    {
        os << mp.val_;
        return os;
    }
private:
    int val_;
};

int main(int argc, char** argv)
{
    std::cout << "Value: " << MyPrint(12) << std::endl;
    return 0;
}

Este método requiere que se inserte el objeto MyPrint en la corriente de su elección. Si realmente necesita la capacidad de cambiar la cual corriente está activa, se puede hacer esto:

class MyPrint
{
public:
    MyPrint(int val, std::ostream& os) : val_(val), os_(os) {}
    friend std::ostream& operator<<(std::ostream& dummy, const MyPrint& mp) 
    {
        mp.os_ << mp.val_;
        return os_;
    }
private:
    int val_;
    std::ostream& os_
};

int main(int argc, char** argv)
{
    std::cout << "Value: " << MyPrint(12, std::cout) << std::endl;
    return 0;
}

Existen dos opciones. El primero, usando lo que ya tiene es:

std::cout << "Value: ";
MyPrint(12, &std::cout);
std::cout << std::endl;

El otro, que es más C ++ - como, es reemplazar MyPrint() con el std::ostream& operator<< apropiado. Ya hay uno para int, así que lo haré uno sólo un poco más complejo:

#include <iostream>

struct X {
    int y;
};

// I'm not bothering passing X as a reference, because it's a
// small object
std::ostream& operator<<(std::ostream& os, const X x)
{
    return os << x.y;
}

int main()
{
    X x;
    x.y = 5;
    std::cout << x << std::endl;
}

No hay manera de hacer lo que usted está esperando por la orden de las funciones se evalúan en.

¿Hay alguna razón en particular que necesita para escribir directamente a la ostream así? Si no, sólo tienen MyPrint devuelva una cadena. Si desea utilizar una corriente dentro MyPrint para generar la salida, sólo tiene que utilizar un strstream y devolver el resultado.

En primer lugar, no hay ninguna razón para no pasar en el ostream por referencia en lugar de un puntero:

std::ostream& MyPrint(int val, std::ostream& out) {
  out << val;
  return out;
}

Si realmente no desea utilizar std::ostream& operator<<(std::ostream& os, TYPE), usted puede hacer esto:

int main(int argc, char** argv){
    std::cout << "Value: ";
    MyPrint(12, std::cout) << std::endl;
    return 0;
}

Después de cambiar el puntero a una referencia, usted puede hacer esto:

#include <iostream>

std::ostream& MyPrint(int val, std::ostream& out) {
    out << val;
    return out;
}

int main(int, char**) {
    MyPrint(11, std::cout << "Value: ") << std::endl; 

    return 0;
}

La sintaxis para MyPrint es esencialmente la de un operator<< desenrollado pero con un argumento extra.

En el caso de que la respuesta es, obviamente:

 std::cout << "Value: " << 12 << std::endl;

Si eso no es lo suficientemente bueno, por favor explique lo de salida que desea ver.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top