Concatene dois literais de cadeia de caracteres

121

Estou lendo C ++ acelerado por Koenig. Ele escreve que "a nova idéia é que podemos usar + para concatenar uma string e uma literal de string - ou, nesse caso, duas strings (mas não duas literais).

Tudo bem, isso faz sentido, suponho. Agora, em dois exercícios separados, destinados a esclarecer isso.

As seguintes definições são válidas?

const string hello = "Hello";

const string message = hello + ",world" + "!";

Agora, tentei executar o procedimento acima e funcionou! Então eu fiquei feliz.

Então eu tentei fazer o próximo exercício;

const string exclam = "!";

const string message = "Hello" + ",world" + exclam;

Isso não funcionou. Agora eu entendo que isso tem algo a ver com o fato de que você não pode concatenar dois literais de seqüência de caracteres, mas não entendo a diferença semântica entre o motivo pelo qual consegui fazer o primeiro exemplo funcionar (não é ", mundo" e "! "literais de duas strings? Isso não deveria ter funcionado?), mas não o segundo.

Arthur Collé
fonte
4
const string message = "Hello" ",world" + exclam(por exemplo, omitir o primeiro +) deve funcionar bem.
n0rd
1
@ Joe - Por que alguém escreveria "Hello" + ", world!"quando você pode fazer "Hello, world!". Como de costume, o C ++ tem uma solução simples e impressionante para um problema percebido. :-)
Bo Persson
2
@Bo A única coisa que posso pensar é se você usar uma definição (#define)
Joe Phillips
@ Joe Mesmo assim, é mais provável que você escreva "Hello" ", world!"(sem o +). Há uma série de reclamações que se pode fazer sobre C ++, mas não acho que o tratamento aqui seja um deles. É exatamente a mesma coisa que se você escrevesse 1 / 3 + 1.5, e reclamou porque a divisão era divisão integral. Para o bem ou para o mal, é assim que a maioria dos idiomas funciona.
James Kanze
2
@Bo Persson Na verdade, esse recurso "hello" " world" == "hello world"é útil se você precisar escrever uma string longa e não desejar que ela saia da janela ou que esteja dentro de alguma restrição de comprimento de linha. Ou se uma das cadeias for definida em uma macro.
precisa

Respostas:

140
const string message = "Hello" + ",world" + exclam;

O +operador tem associatividade da esquerda para a direita, portanto a expressão entre parênteses equivalente é:

const string message = (("Hello" + ",world") + exclam);

Como você pode ver, as duas strings são literais "Hello"e ",world"são "adicionadas" primeiro, daí o erro.

Uma das duas primeiras seqüências de caracteres concatenadas deve ser um std::stringobjeto:

const string message = string("Hello") + ",world" + exclam;

Como alternativa, você pode forçar o segundo +a ser avaliado primeiro entre parênteses à parte da expressão:

const string message = "Hello" + (",world" + exclam);

Faz sentido que o seu primeiro exemplo ( hello + ",world" + "!") funcione porque o std::string( hello) é um dos argumentos à esquerda +. Isso +é avaliado, o resultado é um std::stringobjeto com a sequência concatenada e o resultado std::stringé concatenado com o "!".


Quanto ao motivo pelo qual você não pode concatenar dois literais de string usando +, é porque um literal de string é apenas uma matriz de caracteres (um const char [N]onde Né o comprimento da string mais um, para o terminador nulo). Quando você usa uma matriz na maioria dos contextos, ela é convertida em um ponteiro para seu elemento inicial.

Então, quando você tenta fazer "Hello" + ",world", o que você realmente está tentando fazer é adicionar dois const char*s juntos, o que não é possível (o que significaria adicionar dois ponteiros?) E, se fosse, não faria o que você faria. Queria fazer.


Observe que você pode concatenar literais de string colocando-os um ao lado do outro; por exemplo, os dois seguintes são equivalentes:

"Hello" ",world"
"Hello,world"

Isso é útil se você tiver uma literal de cadeia longa que deseja dividir em várias linhas. Eles precisam ser literais de string: isso não funcionará com const char*ponteiros ou const char[N]matrizes.

James McNellis
fonte
3
Além disso, const string message = "Hello" + (",world"+exclam);também funcionará, devido a parênteses explícitos (isso é uma palavra?).
Chinmay Kanchi
1
Poderia ser ainda mais completo se você apontar para fora porque o primeiro exemplo funciona:const string message = ((hello + ",world") + "!");
Mark Ransom
Obrigado! Eu suspeitava que tivesse algo a ver com associatividade da esquerda para a direita, mas não tinha certeza e essa diferença semântica não fazia muito sentido para mim. Agradeço a resposta!
Arthur Collé 19/05
2
Eu mencionaria que a "Hello" ",world"sintaxe é útil não apenas para quebrar em várias linhas, mas também quando uma das cadeias literais é uma macro (ou mesmo ambas). Em seguida, a concatenação acontece em tempo de compilação.
Melebius
8

Você deve sempre prestar atenção aos tipos .

Embora todos pareçam cordas "Hello"e ",world"sejam literais .

E no seu exemplo, exclamé um std::stringobjeto.

O C ++ possui uma sobrecarga de operador que pega um std::stringobjeto e adiciona outra string a ele. Quando você concatena um std::stringobjeto com um literal, ele cria a conversão apropriada para o literal.

Mas se você tentar concatenar dois literais, o compilador não poderá encontrar um operador que use dois literais.

Yochai Timmer
fonte
Veja std :: operator +, que oferece sobrecargas para concatenar um std::stringcom outro std::string, uma matriz de caracteres ou um único caractere.
precisa saber é o seguinte
7

Seu segundo exemplo não funciona porque não há operator +dois literais de seqüência de caracteres. Observe que uma string literal não é do tipo string, mas é do tipo const char *. Seu segundo exemplo funcionará se você o revisar assim:

const string message = string("Hello") + ",world" + exclam;
Juraj Blaho
fonte
4

Desde o C ++ 14, você pode usar dois literais de cadeias reais :

const string hello = "Hello"s;

const string message = hello + ",world"s + "!"s;

ou

const string exclam = "!"s;

const string message = "Hello"s + ",world"s + exclam;
Thomas Sablik
fonte
2

No caso 1, devido à ordem das operações, você obtém:

(olá + ", mundo") + "!" que resolve Olá! "!" e finalmente olá

No caso 2, como James observou, você obtém:

("Hello" + ", world") + exclam, que é a concat dos literais de 2 strings.

Espero que esteja claro :)

Stephen
fonte
1

A diferença entre uma string (ou, para ser mais preciso std::string) e um literal de caractere é que, para a última, não há um +operador definido. É por isso que o segundo exemplo falha.

No primeiro caso, o compilador pode encontrar um adequado, operator+com o primeiro argumento sendo um stringe o segundo um caractere literal ( const char*), para que ele seja usado. O resultado dessa operação é novamente a string, por isso repete o mesmo truque ao adicionar "!"a ela.

Péter Török
fonte