Gabungkan dua string literal

121

Saya membaca Accelerated C ++ oleh Koenig. Dia menulis bahwa "ide barunya adalah kita dapat menggunakan + untuk menggabungkan string dan string literal - atau, dalam hal ini, dua string (tapi bukan dua string literal).

Baiklah, kurasa ini masuk akal. Sekarang ke dua latihan terpisah yang dimaksudkan untuk menerangi ini.

Apakah definisi berikut ini valid?

const string hello = "Hello";

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

Sekarang, saya mencoba menjalankan yang di atas dan berhasil! Jadi saya senang.

Kemudian saya mencoba melakukan latihan berikutnya;

const string exclam = "!";

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

Ini tidak berhasil. Sekarang saya mengerti itu ada hubungannya dengan fakta bahwa Anda tidak dapat menggabungkan dua string literal, tetapi saya tidak mengerti perbedaan semantik antara mengapa saya berhasil mendapatkan contoh pertama untuk bekerja (bukan ", dunia" dan "! "dua string literal? Bukankah seharusnya ini tidak berhasil?) tapi tidak yang kedua.

Arthur Collé
sumber
4
const string message = "Hello" ",world" + exclam(misalnya menghilangkan yang pertama +) harus bekerja dengan baik.
n0
1
@Joe - Mengapa ada orang yang menulis "Hello" + ", world!"ketika Anda bisa melakukannya "Hello, world!". Seperti biasa C ++ memiliki solusi yang luar biasa dan sederhana untuk masalah yang dirasakan. :-)
Bo Persson
2
@Bo Satu-satunya hal yang dapat saya pikirkan adalah jika Anda menggunakan definisi (#define)
Joe Phillips
@Joe Meski begitu, Anda lebih cenderung menulis "Hello" ", world!"(tanpa +). Ada sejumlah keluhan yang bisa dibuat tentang C ++, tapi menurut saya penanganannya di sini bukan salah satunya. Persis sama seperti jika Anda menulis 1 / 3 + 1.5, dan mengeluh karena divisi itu adalah divisi integral. Baik atau buruk, inilah cara kebanyakan bahasa bekerja.
James Kanze
2
@Bo Persson Sebenarnya fitur "hello" " world" == "hello world"ini berguna jika Anda harus menulis string yang panjang dan tidak ingin keluar dari jendela Anda atau Anda ingin berada dalam penyempitan panjang baris. Atau jika salah satu string ditentukan dalam makro.
Dimitar Slavchev

Jawaban:

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

The +Operator telah kiri ke kanan associativity, sehingga ekspresi kurung setara adalah:

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

Seperti yang Anda lihat, dua string literal "Hello"dan ",world""ditambahkan" terlebih dahulu, maka kesalahannya.

Salah satu dari dua string pertama yang digabungkan harus berupa std::stringobjek:

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

Cara lainnya, Anda dapat memaksa yang kedua +untuk dievaluasi terlebih dahulu dengan memberi tanda kurung bagian ekspresi tersebut:

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

Masuk akal bahwa contoh pertama Anda ( hello + ",world" + "!") berfungsi karena std::string( hello) adalah salah satu argumen paling kiri +. Itu +dievaluasi, hasilnya adalah std::stringobjek dengan string yang digabungkan, dan yang dihasilkan std::stringkemudian digabungkan dengan "!".


Adapun mengapa Anda tidak dapat menggabungkan dua string literal menggunakan +, itu karena literal string hanyalah sebuah array karakter (di const char [N]mana Npanjang string ditambah satu, untuk terminator null). Saat Anda menggunakan larik di sebagian besar konteks, larik akan diubah menjadi penunjuk ke elemen awalnya.

Jadi, ketika Anda mencoba melakukannya "Hello" + ",world", yang sebenarnya Anda coba lakukan adalah menambahkan dua const char*bersama, yang tidak mungkin (apa artinya menambahkan dua petunjuk bersama-sama?) Dan jika itu tidak akan melakukan apa yang Anda lakukan. ingin melakukannya.


Perhatikan bahwa Anda dapat menggabungkan string literal dengan menempatkannya di samping satu sama lain; misalnya, dua hal berikut ini setara:

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

Ini berguna jika Anda memiliki literal string panjang yang ingin Anda bagi menjadi beberapa baris. Namun, mereka harus berupa string literal: ini tidak akan berfungsi dengan const char*pointer atau const char[N]array.

James McNellis
sumber
3
Juga, const string message = "Hello" + (",world"+exclam);akan bekerja juga, karena tanda kurung eksplisit (apakah itu sebuah kata?).
Chinmay Kanchi
1
Bisa lebih lengkap lagi jika Anda menunjukkan mengapa contoh pertama berhasil:const string message = ((hello + ",world") + "!");
Mark Ransom
Terima kasih! Saya curiga itu ada hubungannya dengan asosiasi kiri-ke-kanan tetapi tidak yakin dan perbedaan semantik ini tidak masuk akal bagi saya. Saya menghargai jawabannya!
Arthur Collé
2
Saya akan menyebutkan "Hello" ",world"sintaks ini berguna tidak hanya untuk memecah menjadi beberapa baris tetapi juga ketika salah satu literal string adalah makro (atau bahkan keduanya). Kemudian penggabungan terjadi dalam waktu kompilasi.
Melebius
8

Anda harus selalu memperhatikan jenisnya .

Meskipun semuanya tampak seperti string, "Hello"dan ",world"bersifat literal .

Dan dalam contoh Anda, exclamadalah sebuah std::stringobjek.

C ++ memiliki operator overload yang mengambil std::stringobjek dan menambahkan string lain ke dalamnya. Saat Anda menggabungkan std::stringobjek dengan literal, itu akan membuat casting yang sesuai untuk literal.

Tetapi jika Anda mencoba untuk menggabungkan dua literal, kompilator tidak akan dapat menemukan operator yang membutuhkan dua literal.

Yochai Timmer
sumber
Lihat std :: operator + yang menawarkan kelebihan beban untuk menggabungkan std::stringdengan yang lain std::string, larik karakter, atau satu karakter.
DavidRR
7

Contoh kedua Anda tidak berfungsi karena tidak ada operator +untuk dua string literal. Perhatikan bahwa string literal bukanlah bertipe string, melainkan bertipe const char *. Contoh kedua Anda akan berhasil jika Anda merevisinya seperti ini:

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

Sejak C ++ 14 Anda dapat menggunakan dua literal string nyata :

const string hello = "Hello"s;

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

atau

const string exclam = "!"s;

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

Dalam kasus 1, karena urutan operasi Anda mendapatkan:

(halo + ", dunia") + "!" yang memutuskan untuk halo + "!" dan akhirnya menyapa

Dalam kasus 2, seperti yang dicatat James, Anda mendapatkan:

("Halo" + ", dunia") + seru yang merupakan gabungan dari 2 string literal.

Semoga jelas :)

Stephen
sumber
1

Perbedaan antara string (atau tepatnya, std::string) dan literal karakter adalah tidak ada +operator yang ditentukan. Inilah mengapa contoh kedua gagal.

Dalam kasus pertama, kompilator dapat menemukan yang cocok operator+dengan argumen pertama adalah a stringdan yang kedua adalah karakter literal ( const char*) sehingga digunakan itu. Hasil dari operasi itu lagi-lagi a string, jadi ini mengulangi trik yang sama saat menambahkannya "!".

Péter Török
sumber