Объединить два строковых литерала - PullRequest
115 голосов
/ 19 мая 2011

Я читаю Ускоренный C ++ Кенига.Он пишет, что «новая идея заключается в том, что мы можем использовать + для объединения строки и строкового литерала - или, в этом отношении, двух строк (но не двух строковых литералов).

Хорошо, это имеет смысл, яПредположим, теперь на двух отдельных упражнениях, предназначенных для освещения этого.

Допустимы ли следующие определения?

const string hello = "Hello";

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

Теперь я попытался выполнить вышеизложенное, и это сработало! Так что я был счастлив.

Затем я попытался выполнить следующее упражнение;

const string exclam = "!";

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

Это не сработало. Теперь я понимаю, что это связано с тем, что вы не можете объединить два строковых литерала, но яне понимаю смысловой разницы между тем, почему мне удалось заставить работать первый пример (не «, world» и «!» двух строковых литералов? Разве это не должно работать?), но не вторым.

Ответы [ 5 ]

132 голосов
/ 19 мая 2011
const string message = "Hello" + ",world" + exclam;

Оператор + имеет ассоциативность слева направо, поэтому эквивалентное выражение в скобках:

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

Как видите, два строковых литерала "Hello" и ",world" «добавляются» в первую очередь, поэтому возникает ошибка.

Одна из первых двух сцепляемых строк должна быть std::string объектом:

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

В качестве альтернативы, вы можете принудительно вызвать вторую + нужно сначала вычислить, заключив в скобки эту часть выражения:

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

Имеет смысл, что ваш первый пример (hello + ",world" + "!") работает, потому что std::string (hello) является одним изаргументы слева +.То, что + вычисляется, результатом является std::string объект с объединенной строкой, а полученный std::string затем объединяется с "!".


Что касается зачем Вы не можете объединить два строковых литерала, используя +, это потому, что строковый литерал - это просто массив символов (const char [N], где N - длина строки плюс один, для нулевого терминатора).Когда вы используете массив в большинстве контекстов, он конвертируется в указатель на его начальный элемент.

Итак, когда вы пытаетесь сделать "Hello" + ",world", то, что вы на самом деле пытаетесь сделать, - это добавить два const char* вместе, что невозможно (что бы означало добавить два указателя вместе?) и если бы это было так, то не сделал бы то, что хотел.


Обратите внимание, что вы можете объединять строковые литералы, помещая их рядом друг с другом;например, следующие два эквивалента:

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

Это полезно, если у вас есть длинный строковый литерал, который вы хотите разбить на несколько строк.Однако они должны быть строковыми литералами: это не будет работать с const char* указателями или const char[N] массивами.

8 голосов
/ 19 мая 2011

Обязательно обращайте внимание на типы .

Хотя все они выглядят как строки, "Hello" и ",world" являются литералами .

А в вашем примере exclam - это std::string объект.

C ++ имеет перегрузку оператора, которая принимает объект std::string и добавляет к нему еще одну строку. Когда вы объединяете объект std::string с литералом, он делает соответствующее приведение для литерала.

Но если вы попытаетесь объединить два литерала, компилятор не сможет найти оператор, который принимает два литерала.

6 голосов
/ 19 мая 2011

Ваш второй пример не работает, потому что нет operator + для двух строковых литералов.Обратите внимание, что строковый литерал не имеет типа string, но вместо этого имеет тип const char *.Ваш второй пример будет работать, если вы пересмотрите его следующим образом:

const string message = string("Hello") + ",world" + exclam;
2 голосов
/ 19 мая 2011

В случае 1 из-за порядка операций вы получаете:

(привет + ", мир") + "!" который разрешает привет + "!" и наконец привет

В случае 2, как заметил Джеймс, вы получите:

("Hello" + ", world") + exclam, который является конкатом из двух строковых литералов.

Надеюсь, это понятно :) 1009 *

1 голос
/ 19 мая 2011

Разница между строкой (или, если быть точным, std::string) и символьным литералом заключается в том, что для последнего не определен оператор +.Вот почему второй пример завершается неудачей.

В первом случае компилятор может найти подходящий operator+ с первым аргументом, равным string, а вторым - символьным литералом (const char*), поэтомуиспользовал это.Результатом этой операции снова является string, поэтому он добавляет тот же трюк при добавлении к нему "!".

...