Usando operadores de inserção e controlando o formato

Este tópico mostra como controlar o formato e a criação de operadores de inserção para suas próprias classes. O operador de inserção (<<), que é programado previamente para todos os tipos de dados C++, envia bytes a um objeto de fluxo de saída. Operadores de inserção trabalham com "manipuladores" predefinidos, que são elementos que alteram o formato padrão de argumentos inteiros.

É possível controlar o formato com as seguintes opções:

Largura da Saída

Para alinhar a saída, especifique a largura da saída para cada item colocando o manipulador setw no fluxo ou chamando a width função membro de largura. Este exemplo alinha à direita os valores em uma coluna com pelo menor 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 são adicionados a qualquer valor menor do que 10 caracteres de largura.

Para preencher um campo, use a função membro fill que define o valor do caractere de preenchimento para campos com uma largura especificada. O padrão é um espaço em branco. Para preencher a coluna de números com asteriscos, modifique o loop for anterior da seguinte forma:

for (int i = 0; i <4; i++)
{
    cout.width(10);
    cout.fill('*');
    cout << values[i] << endl;
}

O manipulador 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 as larguras de elementos de dados na mesma linha, use o manipulador 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 membro width é declarada em <iostream>. Se você usar setw ou qualquer outro manipulador com argumentos, deverá incluir <iomanip>. Na saída, as cadeia de caracteres são impressas em um campo de largura 6 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 trunque valores. Se a saída formatada exceder a largura, o valor inteiro será impresso, sujeito a configuração de precisão do fluxo. Ambos setw e width afetam apenas o campo a seguir. A largura do campo será revertida para seu comportamento padrão (a largura necessária) após a impressão de um campo. No entanto, as outras opções de formato de fluxo permanecerão em vigor até serem alteradas.

Alinhamento

Fluxos de saída padrão para o texto alinhado à direita. Para alinhar os nomes do exemplo anterior à esquerda e os números à direita, substitua o loop for da seguinte forma:

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 setiosflags com o enumerador left. Esse enumerador é definido na classe ios portanto, a referência deverá incluir o prefixo ios::. O manipulador resetiosflags desliga 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 a precisão de ponto flutuante é seis. Por exemplo, o número 3466.9768 será impresso como 3466.98. Para alterar a forma como esse valor será impresso, use o manipulador setprecision. O manipulador tem dois sinalizadores: fixed e scientific. Se fixed estiver definido, o número será impresso como 3466,976800. Se scientific estiver definido, será impresso como 3.4669773+003.

Para exibir os números de ponto flutuante mostrados em Alinhamento com um dígito significativo, substitua o loop for da seguinte forma:

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 essa instrução antes do loop for:

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 ios::fixed para ios::scientific, o programa imprimirá:

Zoot    1.2e+00
Jimmy   3.5e+01
Al      6.5e+02
Stan    4.4e+03

Novamente, o programa imprimirá um dígito após a vírgula decimal. Se ios::fixed ou ios::scientific estiver definido, o valor de precisão determinará o número de dígitos após o ponto decimal. Se nenhum sinalizador for definido, o valor de precisão determinará o número total de dígitos significativos. O manipulador resetiosflags limpará esses sinalizadores.

Radix

Os manipuladores dec, oct e hex definem a base padrão para entrada e saída. Por exemplo, se você inserir o manipulador hex no fluxo de saída, o objeto converterá corretamente a representação de dados internos de inteiros em um formato de saída hexadecimal. Os números serão exibidos com dígitos de a a f em letras minúsculas se o sinalizador uppercase estiver limpo (o padrão), caso contrário, serão exibidos em letras maiúsculas. A base padrão é dec (decimal).

Cadeias de caracteres entre aspas (C++14)

Ao inserir uma cadeia de caracteres em um fluxo, será possível recuperar facilmente a mesma cadeia de caracteres chamando a função membro stringstream::str(). No entanto, se você quiser usar o operador de extração para inserir o fluxo em uma nova cadeia de caracteres posteriormente, poderá obter um resultado inesperado porque o operador >>, por padrão, será interrompido 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 corrigido manualmente, mas para tornar o ciclo completo de cadeia de caracteres mais conveniente, C++14 adiciona o manipulador de fluxo std::quoted a <iomanip>. Na inserção, o quoted() envolve a cadeia de caracteres com um delimitador (aspas duplas ' " ', por padrão) e na extração manipula o fluxo para extrair todos os caracteres até encontrar o delimitador final. Aspas inseridas são ignoradas com um caractere de escape ('\\' por padrão).

Os delimitadores estão presentes apenas no objeto de fluxo, portanto, não estão presentes na cadeia de caracteres extraída, mas estão presentes na cadeia de caracteres retornada por basic_stringstream::str.

O comportamento de espaço em branco das operações de inserção e extração é independe de como uma cadeia de caracteres é representada no código, assim, o operador entre aspas será útil mesmo se a cadeia de caracteres de entrada for uma cadeia de caracteres bruta, literal ou regular. A cadeia de caracteres de entrada, independente do seu formato, poderá ter aspas, quebras de linha, tabulações, e assim por diante, que serão preservados pelo manipulador quoted().

Para obter mais informações e exemplos de código completos, consulte quoted.

Confira também

Fluxos de saída