Pregunta

Es bien sabido que el usuario puede definir manipuladores de transmisión como esta:

ostream& tab(ostream & output)
{
    return output<< '\t';
} 

Y esto se puede utilizar en main () como esto:

cout<<'a'<<tab<<'b'<<'c'<<endl;

Por favor, explicar cómo funciona todo esto? Si operador << asume como un segundo parámetro un puntero a la función que toma y vuelve ostream y , por favor explicar mi por qué es necesario? Lo que sería un error si la función no toma y retorno ostream y pero fue vacío en lugar de ostream y ?

También es interesante por qué “DEC”, “hex” manipuladores tiene efecto hasta que no cambio entre ellos, pero manipuladores definidos por el usuario debe ser siempre utilizado con el fin de entrar en vigor para cada una de streaming?

¿Fue útil?

Solución

Los norma define la siguiente sobrecarga operator<< en la plantilla de clase basic_ostream:

basic_ostream<charT,traits>& operator<<(
    basic_ostream<charT,traits>& (*pf) (basic_ostream<charT,traits>&) );

Efectos: Ninguno. No se comporta como una función de la salida con formato (como se describe en 27.6.2.5.1).

Las devoluciones:. pf(*this)

El parámetro es un puntero a una toma de función y devolver una referencia a un std::ostream.

Esto significa que se puede "corriente" de una función con esta firma a un objeto ostream y tiene el efecto de llamar a esa función en la secuencia. Si se utiliza el nombre de una función en una expresión entonces se (por lo general) se convierta en un puntero a esa función.

std::hex es un manipulador std::ios_base define como sigue.

   ios_base& hex(ios_base& str);

Efectos:. Llamadas str.setf(ios_base::hex, ios_base::basefield)

Las devoluciones: Str.

Esto significa que la transmisión de hex a un ostream fijará la base de salida de formato banderas a números de salida en hexadecimal. El manipulador no hace nada salida de sí mismo.

Otros consejos

No hay nada malo en ello excepto que no está sobrecargado << operador definido para ello. Las sobrecargas existentes para << están esperando un manipulador con la firma ostream y (* fp) (ostream y) .

Si usted le dio un manipulador con el tipo ostream y (* fp) () que se obtiene un error de compilación, ya que no tiene una definición para << operador (ostream y, ostream y (* fp) ()) . Si quería esta funcionalidad que tendría que sobrecargar el operador << para aceptar manipuladores de este tipo.

tendría que escribir una definición para esto:
ostream y ostream :: operador << (ostream y (* m) ())

Tenga en cuenta aquí que nada mágico está sucediendo aquí. Las bibliotecas de flujo dependen en gran medida características estándar C ++: la sobrecarga de operadores, clases y referencias.

Ahora que ya sabe cómo se puede crear la funcionalidad que usted describe, aquí es por qué no lo hacemos:

Sin pasar una referencia a la corriente que estamos tratando de manipular, no podemos hacer modificaciones a la corriente conectada al dispositivo final (cin, hacia fuera, err, fstream, etc). La función (de modificadores son todas las funciones sólo con nombres de fantasía) tendrá que o bien devolver una nueva ostream que no tenía nada que ver con el de la izquierda de la << operador, o por medio de algún mecanismo muy feo, averiguar qué ostream lo que debería conectar con los demás todo a la derecha del modificador no hará que el dispositivo final, sino que más bien ser enviados a cualquier ostream la función / modificador devuelto.

Piense en corrientes como este

cout << "something here" << tab << "something else"<< endl;

realmente significa

(((cout << "something here") << tab ) << "something else" ) << endl);

donde cada conjunto de paréntesis, hace algo a cout (escribir, modificar, etc) y luego vuelve Coût por lo que el siguiente conjunto de paréntesis, puede trabajar en él.

Si la pestaña modificador / función no tomó una referencia a un ostream que tendría que adivinar lo que de alguna manera era ostream a la izquierda de la << operador para realizar su tarea. Estabas trabaje con cour, cerr ... alguna secuencia de archivo? Los detalles internos de la función nunca sabrán a menos que se entregan esa información de alguna forma, y ??por qué no es así como ser tan simple como una referencia a él.

Ahora que realmente remachar el clavo, vamos a ver lo que endl es realmente y lo que sobrecarga versión del operador << estamos utilizando:

Este operador es similar al siguiente:

  ostream& ostream::operator<<(ostream& (*m)(ostream&)) 
  {  
      return (*m)(*this);
  }

miradas Endl como esta:

  ostream& endl(ostream& os)      
  {  
      os << '\n'; 
      os.flush();     
      return os;
  }

El propósito de endl es añadir una nueva línea y eliminar la corriente, asegurándose de que todo el contenido del buffer interno de la corriente se han escrito en el dispositivo. Con el fin de hacer esto, primero se tiene que escribir un '\ n' para esta corriente. A continuación, tiene que decirle a la corriente de descarga. La única manera para que endl para saber qué flujo a escribir a ras y es que el operador pasar esa información a la función endl cuando se lo llama. Sería como yo que le dice a lavar mi coche, pero nunca le dice qué coche es mío en el aparcamiento lleno. Nunca sería capaz de hacer su trabajo. Necesitas que cualquier mano que mi coche o me puede lavar a mí mismo.

Espero que borra las cosas

PS -. Si llegara a encontrar accidentalmente mi coche, por favor, lave

Normalmente, el manipulador de flujo establece algunas banderas (u otros ajustes) en el objeto de secuencia, para que la próxima vez que se utiliza, se actuará de acuerdo con las banderas. Por consiguiente, el manipulador devuelve el mismo objeto su pasado. La sobrecarga operator<< que llama el manipulador ya cuenta con este objeto, por supuesto, así como habrá notado, el valor de retorno no es necesario estrictamente para ese caso. Creo que esto cubre todos los manipuladores estándar -. Todos vuelven a su entrada

Sin embargo, con el valor de retorno, el marco es suficientemente flexible para que un manipulador de flujo a medida podría devolver un objeto diferente, presumiblemente un contenedor para el objeto de su dado. Este otro objeto sería entonces regresó de cout << 'a' << tab, y podría hacer algo que el incorporado en la configuración ostream formatear no son compatibles.

No está seguro de cómo le gustaría organizar para este otro objeto para ser liberado, sin embargo, así que no sé qué tan práctico es esto. Puede ser que tiene que ser algo peculiar, como un objeto proxy que está gestionado por el propio ostream. A continuación, el manipulador sería sólo el trabajo de clases de flujo a medida que apoyan activamente, lo que no suele ser el punto de manipuladores.

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