Compartilhar via


Literais de caracteres e de cadeia de caracteres (C++)

O C++ dá suporte a vários tipos de caracteres e cadeia de caracteres e fornece maneiras de expressar os valores literais de cada um desses tipos. No código-fonte, você expressa o conteúdo dos literais de caracteres e de cadeias de caracteres usando um conjunto de caracteres. Nomes de caracteres universais e caracteres de escape permitem que você expresse qualquer cadeia de caracteres usando apenas o conjunto de caracteres de origem básico. Um literal de cadeia de caracteres bruta permite evitar o uso de caracteres de escape e pode ser usado para expressar todos os tipos de literais de cadeia de caracteres. Você também pode criar literais std::string sem precisar executar etapas extras de construção ou conversão.

#include <string>
using namespace std::string_literals; // enables s-suffix for std::string literals

int main()
{
    // Character literals
    auto c0 =   'A'; // char
    auto c1 = u8'A'; // char
    auto c2 =  L'A'; // wchar_t
    auto c3 =  u'A'; // char16_t
    auto c4 =  U'A'; // char32_t

    // Multicharacter literals
    auto m0 = 'abcd'; // int, value 0x61626364

    // String literals
    auto s0 =   "hello"; // const char*
    auto s1 = u8"hello"; // const char* before C++20, encoded as UTF-8,
                         // const char8_t* in C++20
    auto s2 =  L"hello"; // const wchar_t*
    auto s3 =  u"hello"; // const char16_t*, encoded as UTF-16
    auto s4 =  U"hello"; // const char32_t*, encoded as UTF-32

    // Raw string literals containing unescaped \ and "
    auto R0 =   R"("Hello \ world")"; // const char*
    auto R1 = u8R"("Hello \ world")"; // const char* before C++20, encoded as UTF-8,
                                      // const char8_t* in C++20
    auto R2 =  LR"("Hello \ world")"; // const wchar_t*
    auto R3 =  uR"("Hello \ world")"; // const char16_t*, encoded as UTF-16
    auto R4 =  UR"("Hello \ world")"; // const char32_t*, encoded as UTF-32

    // Combining string literals with standard s-suffix
    auto S0 =   "hello"s; // std::string
    auto S1 = u8"hello"s; // std::string before C++20, std::u8string in C++20
    auto S2 =  L"hello"s; // std::wstring
    auto S3 =  u"hello"s; // std::u16string
    auto S4 =  U"hello"s; // std::u32string

    // Combining raw string literals with standard s-suffix
    auto S5 =   R"("Hello \ world")"s; // std::string from a raw const char*
    auto S6 = u8R"("Hello \ world")"s; // std::string from a raw const char* before C++20, encoded as UTF-8,
                                       // std::u8string in C++20
    auto S7 =  LR"("Hello \ world")"s; // std::wstring from a raw const wchar_t*
    auto S8 =  uR"("Hello \ world")"s; // std::u16string from a raw const char16_t*, encoded as UTF-16
    auto S9 =  UR"("Hello \ world")"s; // std::u32string from a raw const char32_t*, encoded as UTF-32
}

Literais de cadeia de caracteres não podem ter nenhum prefixo ou u8, L, u e U para indicar codificações de caracteres estreitos (byte único ou vários bytes), de UTF-8, de caracteres largos (UCS-2 ou UTF-16), de UTF-16 e UTF-32, respectivamente. Um literal de cadeia de caracteres bruta pode ter prefixos R, u8R, LR, uR e UR para os equivalentes de versão bruta dessas codificações. Para criar valores std::string temporários ou estáticos, você pode usar literais de cadeia de caracteres ou literais de cadeia de caracteres bruta com o sufixo s. Para obter mais informações, confira a seção Literal de cadeia de caracteres abaixo. Para obter mais informações sobre o conjunto de caracteres de origem básico, os nomes de caracteres universais e o uso de caracteres de páginas de código estendidas em seu código-fonte, confira Conjuntos de caracteres.

Literais de caracteres

Um caractere literal é composto por um caractere constante. Ele é representado pelo caractere entre aspas simples. Há cinco tipos de literais de caractere:

  • Literais de caractere normais do tipo char, por exemplo 'a'

  • Literais de caracteres UTF-8 do tipo char (char8_t em C++20), por exemplo u8'a'

  • Literais de caractere largo do tipo wchar_t, por exemplo L'a'

  • Literais de caractere UTF-16 do tipo char16_t, por exemplo u'a'

  • Literais de caractere UTF-32 do tipo char32_t, por exemplo U'a'

O caractere usado para um literal de caractere pode ser qualquer caractere, exceto para a barra invertida de caracteres reservados (\), a aspa única (') ou a nova linha. Os caracteres reservados podem ser especificados usando uma sequência de escape. Os caracteres podem ser especificados usando nomes de caracteres universais, desde que o tipo seja grande o suficiente para manter o caractere.

Codificação

Literais de caracteres são codificados de forma diferente com base em seu prefixo.

  • Um literal de caractere sem um prefixo é um literal de caractere comum. O valor de um literal de caractere comum que contém um único caractere, sequência de escape ou nome de caractere universal que pode ser representado no conjunto de caracteres de execução tem um valor igual ao valor numérico de sua codificação no conjunto de caracteres de execução. Um literal de caractere comum que contém mais de um caractere, sequência de escape ou nome de caractere universal é um literal com múltiplos caracteres. Um literal com múltiplos caracteres ou um literal de caractere comum que não pode ser representado no conjunto de caracteres de execução tem tipo int e seu valor é definido pela implementação. Para o MSVC, confira a seção específica da Microsoft abaixo.

  • Um literal de caractere que começa com o prefixo L é um literal de caractere largo. O valor de um literal de caractere largo que contém um único caractere, sequência de escape ou nome de caractere universal tem um valor igual ao valor numérico de sua codificação no conjunto de caracteres largos de execução, a menos que o literal do caractere não tenha representação no conjunto de caracteres largos de execução, nesse caso, o valor é definido pela implementação. O valor de um literal de caractere largo que contém múltiplos caracteres, sequências de escape ou nomes de caracteres universais é definido pela implementação. Para o MSVC, confira a seção específica da Microsoft abaixo.

  • Um literal de caractere que começa com o prefixo u8 é um literal de caractere UTF-8. O valor de um caractere literal UTF-8 que contém um único caractere, uma sequência de escape ou um nome de caractere universal é igual ao seu valor de ponto de código ISO 10646, se puder ser representado por uma única unidade de código UTF-8 (correspondente ao bloco C0 Controls e Basic Latin Unicode). Se o valor não puder ser representado por uma única unidade de código UTF-8, o programa ficará mal formado. Um literal de caractere UTF-8 que contém mais de um caractere, sequência de escape ou nome de caractere universal está mal formado.

  • Um literal de caractere que começa com o prefixo u é um literal de caractere UTF-16. O valor de um literal de caractere UTF-16 que contém um único caractere, sequência de escape ou nome de caractere universal tem um valor igual ao seu valor de ponto de código ISO 10646 se puder ser representado por uma única unidade de código UTF-16 (correspondente ao plano multilíngue básico). Se o valor não puder ser representado por uma única unidade de código UTF-16, o programa ficará mal formado. Um literal de caractere UTF-16 que contém mais de um caractere, sequência de escape ou nome de caractere universal está mal formado.

  • Um literal de caractere que começa com o prefixo U é um literal de caractere UTF-32. O valor de um literal de caractere UTF-32 que contém um único caractere, sequência de escape ou nome de caractere universal tem um valor igual ao valor do ponto de código ISO 10646. Um literal de caractere UTF-32 que contém mais de um caractere, sequência de escape ou nome de caractere universal está mal formado.

Sequências de escape

Existem três tipos de sequências de escape: simples, octal e hexadecimal. As sequências de escape podem ser qualquer um dos seguintes valores:

Valor Sequência de escape
nova linha \n
barra invertida \\
tabulação horizontal \t
ponto de interrogação ? ou \?
tabulação vertical \v
aspas simples \'
backspace \b
aspas duplas \"
retorno de carro \r
o caractere nulo \0
avanço de página \f
octal \ooo
alerta (campainha) \a
hexadecimal \xhhh

Uma sequência de escape octal é uma barra invertida seguida por uma sequência de um a três dígitos octais. Uma sequência de escape octal termina no primeiro caractere que não é um dígito octal, se encontrado antes do terceiro dígito. O maior valor octal possível é \377.

Uma sequência de escape hexadecimal é representada por uma barra invertida, seguida pelo caractere x, seguida por uma sequência de um ou mais dígitos hexadecimais. Zeros à esquerda são ignorados. Em um literal de caractere prefixado u8 ou comum, o maior valor hexadecimal é 0xFF. Em um literal de caractere largo com prefixo L ou U, o maior valor hexadecimal é 0xFFFF. Em um literal de caractere largo com prefixo U, o maior valor hexadecimal é 0xFFFFFFFF.

Este código de exemplo mostra alguns exemplos de caracteres de escape usando literais de caracteres comuns. A mesma sintaxe de sequência de escape é válida para os outros tipos literais de caracteres.

#include <iostream>
using namespace std;

int main() {
    char newline = '\n';
    char tab = '\t';
    char backspace = '\b';
    char backslash = '\\';
    char nullChar = '\0';

    cout << "Newline character: " << newline << "ending" << endl;
    cout << "Tab character: " << tab << "ending" << endl;
    cout << "Backspace character: " << backspace << "ending" << endl;
    cout << "Backslash character: " << backslash << "ending" << endl;
    cout << "Null character: " << nullChar << "ending" << endl;
}
/* Output:
Newline character:
ending
Tab character:  ending
Backspace character:ending
Backslash character: \ending
Null character:  ending
*/

O caractere de barra invertida (\) é um caractere de continuação de linha, quando colocado no final de uma linha. Se desejar que um caractere de barra invertida seja exibido como uma literal de caractere, você deve digitar duas barras invertidas em uma linha (\\). Para obter mais informações sobre o caractere de continuação de linha, confira Fases de Translação.

Específico da Microsoft

Para criar um valor de um literal com múltiplos caracteres estreito, o compilador converte a sequência de caracteres ou o caractere entre aspas simples em valores de 8 bits em um inteiro de 32 bits. Vários caracteres no literal preenchem os bytes correspondentes, conforme necessário, da alta para a baixa ordem. Em seguida, o compilador converte o inteiro no tipo de destino seguindo as regras usuais. Por exemplo, para criar um valor char, o compilador usa o byte de baixa ordem. Para criar um valor wchar_t ou char16_t, o compilador usa a palavra de baixa ordem. O compilador avisa que o resultado será truncado se algum bit estiver definido acima do byte ou da palavra atribuída.

char c0    = 'abcd';    // C4305, C4309, truncates to 'd'
wchar_t w0 = 'abcd';    // C4305, C4309, truncates to '\x6364'
int i0     = 'abcd';    // 0x61626364

Uma sequência de escape octal que parece conter mais de três dígitos é tratada como uma sequência octal de 3 dígitos, seguida pelos dígitos subsequentes como caracteres em um literal de múltiplos caracteres, o que pode dar resultados surpreendentes. Por exemplo:

char c1 = '\100';   // '@'
char c2 = '\1000';  // C4305, C4309, truncates to '0'

Sequências de escape que parecem conter caracteres não octais são avaliadas como uma sequência octal até o último caractere octal, seguida pelos caracteres restantes como os caracteres subsequentes em um literal de múltiplos caracteres. O aviso C4125 será gerado se o primeiro caractere não octal for um dígito decimal. Por exemplo:

char c3 = '\009';   // '9'
char c4 = '\089';   // C4305, C4309, truncates to '9'
char c5 = '\qrs';   // C4129, C4305, C4309, truncates to 's'

Uma sequência de escape octal que tem um valor maior do que \377 causa o erro C2022: 'value-in-decimal': grande demais para o caractere.

Uma sequência de escape que aparenta ter caracteres hexadecimais e não hexadecimais é avaliada como um literal de múltiplos caracteres que contém uma sequência de escape hexadecimal até o último caractere hexadecimal, seguido pelos caracteres não hexadecimais. Uma sequência de escape hexadecimal que não contém nenhum dígito hexadecimal causa o erro de compilador C2153: “literais hex devem possuir pelo menos um dígito hex”.

char c6 = '\x0050'; // 'P'
char c7 = '\x0pqr'; // C4305, C4309, truncates to 'r'

Se um literal de caractere largo prefixado com L contém uma sequência de múltiplos caracteres, o valor é obtido do primeiro caractere e o compilador gera o aviso C4066. Os caracteres subsequentes são ignorados, ao contrário do comportamento do literal de múltiplos caracteres comum equivalente.

wchar_t w1 = L'\100';   // L'@'
wchar_t w2 = L'\1000';  // C4066 L'@', 0 ignored
wchar_t w3 = L'\009';   // C4066 L'\0', 9 ignored
wchar_t w4 = L'\089';   // C4066 L'\0', 89 ignored
wchar_t w5 = L'\qrs';   // C4129, C4066 L'q' escape, rs ignored
wchar_t w6 = L'\x0050'; // L'P'
wchar_t w7 = L'\x0pqr'; // C4066 L'\0', pqr ignored

A seção específica da Microsoft termina aqui.

Nomes de caracteres universais

Em literais de caracteres e de cadeia de caracteres nativos (não brutos), qualquer caractere pode ser representado por um nome de caractere universal. Os nomes de caracteres universais são formados por um prefixo \U seguido por um ponto de código Unicode de oito dígitos ou por um prefixo \u seguido por um ponto de código Unicode de quatro dígitos. Todos os oito ou quatro dígitos, respectivamente, devem estar presentes para fazer um nome de caractere universal bem formado.

char u1 = 'A';          // 'A'
char u2 = '\101';       // octal, 'A'
char u3 = '\x41';       // hexadecimal, 'A'
char u4 = '\u0041';     // \u UCN 'A'
char u5 = '\U00000041'; // \U UCN 'A'

Pares alternativos

Nomes de caracteres universais não podem codificar valores no intervalo de pontos de código alternativo D800-DFFF. Para pares alternativos Unicode, especifique o nome do caractere universal usando \UNNNNNNNN, em que NNNNNNNN é o ponto de código de oito dígitos para o caractere. O compilador gera um par alternativo, se necessário.

No C++03, a linguagem permitia que apenas um subconjunto de caracteres fosse representado por seus nomes de caracteres universais e permitia alguns nomes de caracteres universais que não representavam nenhum caractere Unicode válido. Esse erro foi corrigido no padrão C++11. No C++11, tanto os literais de caracteres e de cadeias de caracteres quanto os identificadores podem usar nomes de caracteres universais. Para obter mais informações sobre nomes de caracteres universais, confira Conjuntos de caracteres. Para obter mais informações sobre o Unicode, confira Unicode. Para obter mais informações sobre pares alternativos, confira Pares alternativos e caracteres suplementares.

Literais de cadeia de caracteres

Uma literal de cadeia de caracteres representa uma sequência de caracteres que, juntos, formam uma cadeia de caracteres terminada em nulo. Os caracteres devem ser incluídos entre aspas duplas. Existem os seguintes tipos de literais de cadeias de caracteres:

Literais de cadeia de caracteres estreitas

A literal de cadeia de caracteres estreita é uma matriz de tipo const char[n] não prefixada, delimitada por aspas duplas e terminada em nulo, em que n é o comprimento da matriz em bytes. A literal de cadeia de caracteres estreita pode conter qualquer caractere gráfico, exceto a aspa dupla ("), barra invertida (\) ou caractere de nova linha. A literal de cadeia de caracteres estreita também pode conter as sequências de escape listadas acima e nomes de caracteres universais que se encaixam em um byte.

const char *narrow = "abcd";

// represents the string: yes\no
const char *escaped = "yes\\no";

Cadeias de caracteres codificadas UTF-8

A cadeia de caracteres codificada UTF-8 é uma matriz de tipo const char[n] prefixada u8, delimitada por aspas duplas e terminada em nulo, em que n é o comprimento da matriz codificada em bytes. A literal de cadeia de caracteres prefixada u8 pode conter qualquer caractere gráfico, exceto a aspa dupla ("), barra invertida (\) ou caractere de nova linha. A cadeia de caracteres com prefixo u8 também pode conter as sequências de escape listadas acima e qualquer nome de caractere universal.

O C++20 apresenta o tipo de caractere (Unicode codificado em UTF-8 de 8 bits) portátil char8_t. Em C++20, prefixos literais u8 especificam caracteres ou cadeias de caracteres de char8_t, em vez de char.

// Before C++20
const char* str1 = u8"Hello World";
const char* str2 = u8"\U0001F607 is O:-)";
// C++20 and later
const char8_t* u8str1 = u8"Hello World";
const char8_t* u8str2 = u8"\U0001F607 is O:-)";

Literais da cadeia de caracteres largas

Uma literal de cadeia de caracteres larga é uma matriz terminada em nulo da constante wchar_t que é prefixada em 'L' e contém qualquer caractere gráfico exceto as aspas duplas ("), a barra invertida (\) ou o caractere de nova linha. Um literal de cadeia larga pode conter as sequências de escape listadas acima e qualquer nome de caractere universal.

const wchar_t* wide = L"zyxw";
const wchar_t* newline = L"hello\ngoodbye";

char16_t e char32_t (C++11)

O C++11 apresenta os tipos de caracteres portáteis char16_t (Unicode de 16 bits) e char32_t (Unicode de 32 bits):

auto s3 = u"hello"; // const char16_t*
auto s4 = U"hello"; // const char32_t*

Literais de cadeia de caracteres bruta (C++11)

Uma literal de cadeia de caracteres bruta é uma matriz terminada em nulo (de qualquer tipo de caractere) que contém qualquer caractere gráfico, inclusive as aspas duplas ("), a barra invertida (\) ou o caractere de nova linha. As literais de cadeias de caracteres brutas costumam ser usadas em expressões regulares que utilizam classes de caracteres, bem como em cadeias de caracteres HTML e XML. Para obter exemplos, confira o seguinte artigo: Perguntas frequentes de Bjarne Stroustrup sobre o C++11.

// represents the string: An unescaped \ character
const char* raw_narrow = R"(An unescaped \ character)";
const wchar_t*  raw_wide  = LR"(An unescaped \ character)";
const char*     raw_utf8a = u8R"(An unescaped \ character)"; // Before C++20
const char8_t*  raw_utf8b = u8R"(An unescaped \ character)"; // C++20
const char16_t* raw_utf16 = uR"(An unescaped \ character)";
const char32_t* raw_utf32 = UR"(An unescaped \ character)";

Um delimitador é uma sequência definida pelo usuário, com até 16 caracteres, que vem imediatamente antes do parêntese de abertura de uma literal de cadeia de caracteres bruta e imediatamente depois do parêntese de fechamento. Por exemplo, em R"abc(Hello"\()abc" a sequência de delimitador está abc e o conteúdo da cadeia de caracteres é Hello"\(. Você pode usar um delimitador para desambiguizar cadeias de caracteres brutas que contenham tanto aspas duplas quanto parênteses. Esta literal de cadeia de caracteres causa um erro do compilador:

// meant to represent the string: )"
const char* bad_parens = R"()")";  // error C2059

Mas um delimitador resolve essa sintaxe:

const char* good_parens = R"xyz()")xyz";

Você pode construir uma literal de cadeia de caracteres bruta que contém uma nova linha (não o caractere de escape) na origem:

// represents the string: hello
//goodbye
const wchar_t* newline = LR"(hello
goodbye)";

std::string literals (C++14)

std::string literais são implementações da Biblioteca Padrão de literais definidos pelo usuário (veja abaixo) que são representados como "xyz"s (com um sufixo s). Esse tipo de literal de cadeia de caracteres produz um objeto temporário do tipostd::string, std::wstring, std::u32string ou std::u16string, dependendo do prefixo especificado. Quando nenhum prefixo é usado, como acima, um std::string é produzido. L"xyz"s produz uma std::wstring. u"xyz"s produz uma std::u16string e U"xyz"s produz uma std::u32string.

//#include <string>
//using namespace std::string_literals;
string str{ "hello"s };
string str2{ u8"Hello World" };     // Before C++20
u8string u8str2{ u8"Hello World" }; // C++20
wstring str3{ L"hello"s };
u16string str4{ u"hello"s };
u32string str5{ U"hello"s };

O sufixo s também pode ser usado em literais de string brutas:

u32string str6{ UR"(She said "hello.")"s };

std::string literais são definidos no namespace std::literals::string_literals no arquivo de cabeçalho de <cadeia de caracteres>. Porque std::literals::string_literals, e std::literals ambos são declarados como namespaces embutidos, std::literals::string_literals é tratado automaticamente como se pertencesse diretamente ao namespace std.

Tamanho das literais de cadeias de caracteres

Para cadeias de caracteres ANSI char* e outras codificações de byte único (mas não UTF-8), o tamanho (em bytes) de uma literal de cadeia de caracteres é o número de caracteres mais 1 para o caractere nulo final. Para todos os outros tipos de cadeia de caracteres, o tamanho não está estritamente relacionado ao número de caracteres. UTF-8 usa até quatro elementos char para codificar algumas unidades de código e char16_t ou wchar_t codificado como UTF-16 pode usar dois elementos (para um total de quatro bytes) para codificar uma única unidade de código. Este exemplo mostra o tamanho de uma cadeia literal larga em bytes.

const wchar_t* str = L"Hello!";
const size_t byteSize = (wcslen(str) + 1) * sizeof(wchar_t);

Observe que strlen() e wcslen() não inclua o tamanho do caractere nulo de terminação, cujo tamanho é igual ao tamanho do elemento do tipo de cadeia de caracteres: um byte em uma cadeia de caracteres char* ou char8_t*, dois bytes em uma cadeia de caracteres de wchar_t* ou char16_t* e quatro bytes em cadeias de caracteres char32_t*.

Comprimento máximo de um literal de cadeia de caracteres após a concatenação:

  • Visual Studio antes da versão 17.0 de 2022: o comprimento máximo de um literal de cadeia de caracteres após a concatenação é de 65.535 bytes. Isso se aplica a literais de cadeia de caracteres estreitas e largas.
  • A partir da versão 17.0 do Visual Studio 2022: o comprimento máximo de um literal de cadeia de caracteres após a concatenação é limitado apenas pela memória disponível. No entanto, o limite de tamanho antes da concatenação ainda é de 16.384 bytes

Modificar literais de cadeias de caracteres

Como as literais de cadeias de caracteres (não incluindo literais std::string) são constantes, tentar modificá-las (por exemplo, str[2] = 'A') causa um erro do compilador.

Específico da Microsoft

No Microsoft C++, você pode usar uma literal de cadeia de caracteres para inicializar um ponteiro para a não constante char ou wchar_t. Essa inicialização não constante é permitida no código C99, mas foi preterida no C++98 e removida no C++11. Uma tentativa de modificar a cadeia de caracteres causa uma violação de acesso, como neste exemplo:

wchar_t* str = L"hello";
str[2] = L'a'; // run-time error: access violation

Você pode fazer com que o compilador emita um erro quando uma literal de cadeia de caracteres é convertida em um ponteiro de caractere não constante ao definir a opção de compilador /Zc:strictStrings (Desativar conversão de tipo literal de cadeia de caracteres). Recomendamos isso para código portátil compatível com padrões. Também é uma boa prática usar a palavra-chave auto para declarar ponteiros inicializados por literais de cadeias de caracteres, pois ela é resolvida para o tipo correto (const). Este exemplo de código mostra uma tentativa de gravar em uma literal de cadeia de caracteres em tempo de compilação:

auto str = L"hello";
str[2] = L'a'; // C3892: you cannot assign to a variable that is const.

Em alguns casos, literais de cadeias de caracteres idênticas podem ser agrupadas para economizar espaço no arquivo executável. Em pools de literais de cadeias de caracteres, o compilador faz com que todas as referências a uma literal de cadeia de caracteres específica apontem para o mesmo local na memória, em vez de cada referência apontar para uma instância separada da literal. Para habilitar o agrupamento de cadeias de caracteres em pools, use a opção de compilador /GF.

A seção específica da Microsoft termina aqui.

Concatenando literais de cadeias de caracteres adjacentes

Literais de cadeia de caracteres largos ou estreitos adjacentes são concatenados. Esta declaração:

char str[] = "12" "34";

é idêntica a esta declaração:

char atr[] = "1234";

e a esta declaração:

char atr[] =  "12\
34";

Usar códigos de escape hexadecimais inseridos para especificar literais de cadeias de caracteres pode causar resultados inesperados. O exemplo a seguir visa criar uma literal de cadeia de caracteres que contenha o caractere ASCII 5, seguido pelos caracteres "f", "i", "v" e "e":

"\x05five"

O resultado real é um 5F hexadecimal, que é o código ASCII de um sublinhado, seguido pelos caracteres i, v e e. Para obter o resultado correto, você pode usar uma destas sequências de escape:

"\005five"     // Use octal literal.
"\x05" "five"  // Use string splicing.

std::string literais (e relacionados std::u8string, std::u16string e std::u32string) podem ser concatenados com o operador + definido para tipos basic_string. Eles também podem ser concatenados da mesma forma que literais de cadeia de caracteres adjacentes. Em ambos os casos, a codificação de cadeia de caracteres e o sufixo devem corresponder:

auto x1 = "hello" " " " world"; // OK
auto x2 = U"hello" " " L"world"; // C2308: disagree on prefix
auto x3 = u8"hello" " "s u8"world"z; // C3688, disagree on suffixes

Literais de cadeia de caracteres com nomes de caracteres universais

Literais de cadeia de caracteres nativos (não brutos) podem usar nomes de caracteres universais para representar qualquer caractere, desde que o nome do caractere universal possa ser codificado como um ou mais caracteres no tipo de cadeia de caracteres. Por exemplo, um nome de caractere universal que representa um caractere estendido não pode ser codificado em uma cadeia de caracteres estreita usando a página de código ANSI, mas pode ser codificado em cadeias de caracteres estreitas em algumas páginas de código de vários bytes ou em cadeias de caracteres UTF-8 ou em uma cadeia de caracteres larga. No C++11, o suporte unicode é estendido pelos tipos de cadeia de caracteres char16_t* e char32_t* e C++20 o estende para o tipo char8_t:

// ASCII smiling face
const char*     s1 = ":-)";

// UTF-16 (on Windows) encoded WINKING FACE (U+1F609)
const wchar_t*  s2 = L"😉 = \U0001F609 is ;-)";

// UTF-8  encoded SMILING FACE WITH HALO (U+1F607)
const char*     s3a = u8"😇 = \U0001F607 is O:-)"; // Before C++20
const char8_t*  s3b = u8"😇 = \U0001F607 is O:-)"; // C++20

// UTF-16 encoded SMILING FACE WITH OPEN MOUTH (U+1F603)
const char16_t* s4 = u"😃 = \U0001F603 is :-D";

// UTF-32 encoded SMILING FACE WITH SUNGLASSES (U+1F60E)
const char32_t* s5 = U"😎 = \U0001F60E is B-)";

Confira também

Conjuntos de caracteres
Literais de ponteiro, numéricos e boolianos
Literais definidos pelo usuário