Usando operadores de inserção e controlando o formato
Este tópico mostra como controlar o formato e como criar operadores de inserção para suas próprias classes. O operador de inserção (<<
), que é pré-programado para todos os tipos de dados C++ padrão, envia bytes para um objeto de fluxo de saída. Os operadores de inserção trabalham com "manipuladores" predefinidos, que são elementos que alteram o formato padrão de argumentos inteiros.
Você pode controlar o formato com as seguintes opções:
Largura de saída
Para alinhar a saída, especifique a largura de saída para cada item colocando o manipulador de setw
no fluxo ou chamando a função de membro width
. Este exemplo alinha à direita os valores em uma coluna com pelo menos 10 caracteres de largura:
// output_width.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
int main( )
{
double values[] = { 1.23, 35.36, 653.7, 4358.24 };
for( int i = 0; i < 4; i++ )
{
cout.width(10);
cout << values[i] << '\n';
}
}
1.23
35.36
653.7
4358.24
Os espaços em branco à esquerda são adicionados a qualquer valor com menos de 10 caracteres de largura.
Para preencher um campo, use a função de membro fill
, que define o valor do caractere de preenchimento para campos que têm uma largura especificada. O padrão é um espaço em branco. Para preencher a coluna de números com asteriscos, modifique o loop de for
anterior da seguinte maneira:
for (int i = 0; i <4; i++)
{
cout.width(10);
cout.fill('*');
cout << values[i] << endl;
}
O manipulador de endl
substitui o caractere de nova linha ('\n'
). A saída tem esta aparência:
******1.23
*****35.36
*****653.7
***4358.24
Para especificar larguras para elementos de dados na mesma linha, use o manipulador de setw
:
// setw.cpp
// compile with: /EHsc
#include <iostream>
#include <iomanip>
using namespace std;
int main( )
{
double values[] = { 1.23, 35.36, 653.7, 4358.24 };
const char *names[] = { "Zoot", "Jimmy", "Al", "Stan" };
for( int i = 0; i < 4; i++ )
cout << setw( 7 ) << names[i]
<< setw( 10 ) << values[i] << endl;
}
A função de membro width
é declarada em <iostream>
. Se você usar setw
ou qualquer outro manipulador com argumentos, você deve incluir <iomanip>
. Na saída, as cadeias de caracteres imprimem em um campo de largura 7 e inteiros em um campo de largura 10:
Zoot 1.23
Jimmy 35.36
Al 653.7
Stan 4358.24
setw
e width
não truncam valores. Se a saída formatada exceder a largura, todo o valor será impresso, sujeito à configuração de precisão do fluxo. Tanto setw
quanto width
afetam apenas o campo a seguir. A largura do campo reverte para seu comportamento padrão (a largura necessária) depois que um campo é impresso. No entanto, as outras opções de formato de fluxo permanecem em vigor até serem alteradas.
Alinhamento
Os fluxos de saída são padronizados para texto alinhado à direita. Para alinhar à esquerda os nomes no exemplo anterior e alinhar à direita os números, substitua o loop for
da seguinte maneira:
for (int i = 0; i <4; i++)
cout << setiosflags(ios::left)
<< setw(6) << names[i]
<< resetiosflags(ios::left)
<< setw(10) << values[i] << endl;
A saída tem esta aparência:
Zoot 1.23
Jimmy 35.36
Al 653.7
Stan 4358.24
O sinalizador de alinhamento à esquerda é definido usando o manipulador de setiosflags
com o enumerador left
. Esse enumerador é definido na classe ios
, portanto, sua referência deve incluir o prefixo ios::
. O manipulador de resetiosflags
desativa o sinalizador de alinhamento à esquerda. Ao contrário de width
e setw
, o efeito de setiosflags
e resetiosflags
é permanente.
Precisão
O valor padrão para precisão de ponto flutuante é seis. Por exemplo, o número 3466.9768 é impresso como 3466.98. Para alterar a forma como esse valor é impresso, use o manipulador de setprecision
. O manipulador tem duas bandeiras: fixed
e scientific
. Se fixed
estiver definido, o número será impresso como 3466.976800. Se scientific
estiver definido, ele será impresso como 3,4669773+003.
Para exibir os números de vírgula flutuante mostrados em de alinhamento com um dígito significativo, substitua o loop de for
da seguinte maneira:
for (int i = 0; i <4; i++)
cout << setiosflags(ios::left)
<< setw(6)
<< names[i]
<< resetiosflags(ios::left)
<< setw(10)
<< setprecision(1)
<< values[i]
<< endl;
O programa imprime esta lista:
Zoot 1
Jimmy 4e+01
Al 7e+02
Stan 4e+03
Para eliminar a notação científica, insira esta declaração antes do for
loop:
cout << setiosflags(ios::fixed);
Com notação fixa, o programa imprime com um dígito após a vírgula decimal.
Zoot 1.2
Jimmy 35.4
Al 653.7
Stan 4358.2
Se você alterar o sinalizador de ios::fixed
para ios::scientific
, o programa imprime isso:
Zoot 1.2e+00
Jimmy 3.5e+01
Al 6.5e+02
Stan 4.4e+03
Novamente, o programa imprime um dígito após o ponto decimal. Se ios::fixed
ou ios::scientific
estiver definido, o valor de precisão determinará o número de dígitos após a vírgula decimal. Se nenhum sinalizador estiver definido, o valor de precisão determinará o número total de dígitos significativos. O manipulador de resetiosflags
limpa essas bandeiras.
Radix
Os manipuladores dec
, oct
e hex
definem o radix padrão para entrada e saída. Por exemplo, se você inserir o manipulador de hex
no fluxo de saída, o objeto traduzirá corretamente a representação de dados internos de inteiros em um formato de saída hexadecimal. Os números são exibidos com dígitos de a a f em minúsculas se o sinalizador de uppercase
estiver claro (o padrão); caso contrário, eles serão exibidos em maiúsculas. O radix padrão é dec
(decimal).
Cadeias de caracteres entre aspas (C++14)
Quando você insere uma cadeia de caracteres em um fluxo, você pode facilmente recuperar a mesma cadeia de caracteres chamando a função de membro stringstream::str()
. No entanto, se você quiser usar o operador de extração para inserir o fluxo em uma nova cadeia de caracteres em um ponto posterior, você pode obter um resultado inesperado porque o operador >>
por padrão irá parar quando encontrar o primeiro caractere de espaço em branco.
std::stringstream ss;
std::string inserted = "This is a sentence.";
std::string extracted;
ss << inserted;
ss >> extracted;
std::cout << inserted; // This is a sentence.
std::cout << extracted; // This
Esse comportamento pode ser superado manualmente, mas para tornar a string round-tripping mais conveniente, o C++14 adiciona o manipulador de fluxo de std::quoted
em <iomanip>
. Após a inserção, quoted()
envolve a string com um delimitador (aspas duplas ' " ' por padrão) e após a extração manipula o fluxo para extrair todos os caracteres até que o delimitador final seja encontrado. Todas as aspas incorporadas são escapadas com um caractere de escape ('\\' por padrão).
Os delimitadores estão presentes apenas no objeto de fluxo; eles não estão presentes na string extraída, mas estão presentes na string retornada por basic_stringstream::str
.
O comportamento de espaço em branco das operações de inserção e extração é independente de como uma cadeia de caracteres é representada no código, portanto, o operador entre aspas é útil independentemente de a cadeia de caracteres de entrada ser uma cadeia de caracteres bruta literal ou uma cadeia de caracteres regular. A cadeia de entrada, seja qual for o seu formato, pode ter aspas incorporadas, quebras de linha, tabulações e assim por diante, e tudo isso será preservado pelo manipulador de quoted()
.
Para obter mais informações e exemplos de código completo, consulte quoted
.