Recientemente tuve un problema para crear un stringstream
debido al hecho de que asumí incorrectamente std::setw()
que afectaría el flujo de cadena para cada inserción, hasta que lo cambié explícitamente. Sin embargo, siempre se desarma después de la inserción.
// With timestruct with value of 'Oct 7 9:04 AM'
std::stringstream ss;
ss.fill('0'); ss.setf(ios::right, ios::adjustfield);
ss << setw(2) << timestruct.tm_mday;
ss << timestruct.tm_hour;
ss << timestruct.tm_min;
std::string filingTime = ss.str(); // BAD: '0794'
Entonces, tengo una serie de preguntas:
- ¿Por qué es
setw()
así? - ¿Hay otros manipuladores de esta manera?
- ¿Hay alguna diferencia en el comportamiento entre
std::ios_base::width()
ystd::setw()
? - Finalmente, ¿hay una referencia en línea que documente claramente este comportamiento? La documentación de mi proveedor (MS Visual Studio 2005) no parece mostrar esto claramente.
Respuestas:
Notas importantes de los comentarios a continuación:
Por Martin:
Por Charles:
La siguiente es la discusión que lleva a la conclusión anterior:
Mirando el código, los siguientes manipuladores devuelven un objeto en lugar de una secuencia:
Esta es una técnica común para aplicar una operación solo al siguiente objeto que se aplica a la secuencia. Lamentablemente, esto no impide que sean pegajosos. Las pruebas indican que todas ellas, excepto
setw
las adhesivas.Todos los demás manipuladores devuelven un objeto de flujo. Por lo tanto, cualquier información de estado que cambien debe registrarse en el objeto de flujo y, por lo tanto, es permanente (hasta que otro manipulador cambie el estado). Por lo tanto, los siguientes manipuladores deben ser manipuladores fijos .
Estos manipuladores realmente realizan una operación en el flujo en sí mismo en lugar del objeto del flujo (aunque técnicamente el flujo es parte del estado de los objetos del flujo). Pero no creo que afecten a ninguna otra parte del estado de los objetos de flujo.
La conclusión es que setw parece ser el único manipulador en mi versión que no es pegajoso.
Para Charles, un simple truco para afectar solo el siguiente elemento de la cadena:
Aquí hay un ejemplo de cómo un objeto puede usarse para cambiar temporalmente el estado y luego volver a colocarlo mediante el uso de un objeto:
fuente
operator<<
para el manipulador asegura que el estado del flujo se cambie de cierta manera. Ninguno de los dos formularios configura ningún tipo de centinela estatal. Es solo el comportamiento de la siguiente operación de inserción formateada lo que determina qué parte del estado se restablece, si corresponde.setw
parece comportarse de manera diferente es porque hay requisitos en las operaciones de salida formateadas para explícitamente.width(0)
la secuencia de salida.La razón por la que
width
no parece ser "permanente" es que se garantiza que ciertas operaciones invoquen.width(0)
una secuencia de salida. Esos son:21.3.7.9 [lib.string.io]:
22.2.2.2.2 [lib.facet.num.put.virtuals]: todas las
do_put
sobrecargas de lanum_put
plantilla. Estos son utilizados por sobrecargas deoperator<<
tomar unbasic_ostream
tipo numérico incorporado.22.2.6.2.2 [lib.locale.money.put.virtuals]: todas las
do_put
sobrecargas de lamoney_put
plantilla.27.6.2.5.4 [lib.ostream.inserters.character]: Sobrecargas de
operator<<
tomar unbasic_ostream
y uno del tipo char de la instanciación basic_ostream ochar
, firmadochar
ounsigned char
o punteros a matrices de estos tipos char.Para ser honesto, no estoy seguro de la razón de esto, pero ningún otro estado de un
ostream
debe restablecerse mediante funciones de salida formateadas. Por supuesto, cosas comobadbit
yfailbit
pueden establecerse si hay una falla en la operación de salida, pero eso debería esperarse.La única razón por la que puedo pensar para restablecer el ancho es que puede ser sorprendente si, al intentar generar algunos campos delimitados, sus delimitadores se rellenan.
P.ej
Para 'corregir' esto tomaría:
mientras que con un ancho de reinicio, la salida deseada se puede generar con el más corto:
fuente
setw()
solo afecta la siguiente inserción. Así es como sesetw()
comporta. El comportamiento desetw()
es el mismo queios_base::width()
. Obtuve misetw()
información de cplusplus.com .Puede encontrar una lista completa de manipuladores aquí . Desde ese enlace, todos los indicadores de flujo deberían decir establecido hasta que otro manipulador los cambie. Una nota sobre el
left
,right
yinternal
manipuladores: Son como las otras banderas y no persisten hasta que se cambie. Sin embargo, solo tienen efecto cuando se establece el ancho de la secuencia, y el ancho debe establecerse en cada línea. Así por ejemplote daría
pero
te daría
Los manipuladores de entrada y salida no son fijos y solo ocurren una vez donde se usan. Los manipuladores parametrizados son diferentes, aquí hay una breve descripción de cada uno:
setiosflags
le permite configurar banderas manualmente, una lista de las cuales puede encontrar aquí , por lo que es pegajosa.resetiosflags
se comporta de forma similar asetiosflags
excepto que desarma los indicadores especificados.setbase
establece la base de los enteros insertados en la secuencia (de modo que 17 en la base 16 sería "11", y en la base 2 sería "10001").setfill
establece el carácter de relleno para insertar en la secuencia cuandosetw
se usa.setprecision
establece la precisión decimal que se utilizará al insertar valores de coma flotante.setw
hace que solo la siguiente inserción tenga el ancho especificado rellenando con el carácter especificado ensetfill
fuente
std::hex
tampoco es pegajoso y, obviamente,std::flush
ostd::setiosflags
tampoco es pegajoso. Entonces no creo que sea tan simple.std::hex
no ser pegajosa estaba equivocada, también lo descubrí. Sin embargo, los indicadores de transmisión pueden cambiar incluso si no inserta unostd::setiosflags
nuevamente, por lo que uno podría ver esto como no adhesivo. Además,std::ws
tampoco es pegajoso. Por lo que es no que fácil.