Я читаю Accelerated C ++ от Koenig. Он пишет, что «новая идея состоит в том, что мы можем использовать + для объединения строки и строкового литерала - или, если на то пошло, двух строк (но не двух строковых литералов).
Хорошо, я полагаю, это имеет смысл. Теперь о двух отдельных упражнениях, призванных прояснить это.
Верны ли следующие определения?
const string hello = "Hello";
const string message = hello + ",world" + "!";
Теперь я попытался выполнить описанное выше, и это сработало! Так что я был счастлив.
Затем я попытался сделать следующее упражнение;
const string exclam = "!";
const string message = "Hello" + ",world" + exclam;
Это не сработало. Теперь я понимаю, что это как-то связано с тем фактом, что вы не можете объединить два строковых литерала, но я не понимаю семантической разницы между тем, почему мне удалось заставить работать первый пример (это не «, world» и «! «два строковых литерала? Разве это не должно было работать?), но не второй.
const string message = "Hello" ",world" + exclam
(например, пропуская первое+
), все будет работать нормально."Hello" + ", world!"
если ты можешь"Hello, world!"
. Как обычно, в C ++ есть удивительный и простой способ решения предполагаемой проблемы. :-)"Hello" ", world!"
(без+
). К C ++ можно предъявить ряд претензий, но я не думаю, что его рассмотрение здесь - одна из них. Это точно так же, как если бы вы писали1 / 3 + 1.5
и жаловались, потому что разделение было целым. Хорошо это или плохо, но так работает большинство языков."hello" " world" == "hello world"
полезна, если вам нужно написать длинную строку и вы не хотите, чтобы она выходила из вашего окна, или если вы хотите быть в пределах некоторого ограничения длины строки. Или если одна из строк определена в макросе.Ответы:
+
Оператор слева на правую ассоциативность, так что эквивалентно в скобках выражение:Как видите, сначала «добавляются» два строковых литерала
"Hello"
и",world"
, отсюда и ошибка.Одна из первых двух конкатенируемых строк должна быть
std::string
объектом:В качестве альтернативы вы можете принудительно
+
вычислить вторую часть выражения, заключив ее в скобки:Имеет смысл, что ваш первый пример (
hello + ",world" + "!"
) работает, потому чтоstd::string
(hello
) является одним из аргументов слева+
. Это+
оценивается, результатом являетсяstd::string
объект с объединенной строкой, и этот результатstd::string
затем объединяется с"!"
.Что касается того, почему вы не можете объединить два строковых литерала, используя
+
, это потому, что строковый литерал является просто массивом символов (const char [N]
гдеN
- длина строки плюс один для нулевого терминатора). Когда вы используете массив в большинстве случаев, он преобразуется в указатель на его начальный элемент.Итак, когда вы пытаетесь сделать
"Hello" + ",world"
, то на самом деле вы пытаетесь сложить дваconst char*
вместе, что невозможно (что бы значило сложить два указателя вместе?), И если бы это было так, то не получилось бы того, что вы хотел это сделать.Обратите внимание, что вы можете объединить строковые литералы, поместив их рядом друг с другом; например, следующие два эквивалентны:
Это полезно, если у вас есть длинный строковый литерал, который вы хотите разбить на несколько строк. Однако они должны быть строковыми литералами: это не будет работать с
const char*
указателями илиconst char[N]
массивами.источник
const string message = "Hello" + (",world"+exclam);
тоже будет работать из-за явных скобок (это слово?).const string message = ((hello + ",world") + "!");
"Hello" ",world"
синтаксис полезен не только для разбиения на несколько строк, но и когда один из строковых литералов является макросом (или даже обоими). Затем конкатенация происходит во время компиляции.Всегда следует обращать внимание на типы .
Хотя все они кажутся строками,
"Hello"
а",world"
являются литералами .А в вашем примере
exclam
этоstd::string
объект.В C ++ есть перегрузка оператора, которая берет
std::string
объект и добавляет к нему другую строку. Когда вы объединяетеstd::string
объект с литералом, он выполняет соответствующее приведение для литерала.Но если вы попытаетесь объединить два литерала, компилятор не сможет найти оператор, который принимает два литерала.
источник
std::string
с другимstd::string
, массивом символов или одиночным символом.Ваш второй пример не работает, потому что нет
operator +
двух строковых литералов. Обратите внимание, что строковый литерал имеет не типstring
, а типconst char *
. Ваш второй пример будет работать, если вы измените его следующим образом:источник
Начиная с C ++ 14 вы можете использовать два реальных строковых литерала :
или
источник
В случае 1 из-за порядка операций вы получаете:
(привет + ", мир") + "!" который преобразуется в hello + "!" и, наконец, привет
В случае 2, как заметил Джеймс, вы получите:
("Привет" + ", мир") + восклицательный знак, который является объединением двух строковых литералов.
Надеюсь, все понятно :)
источник
Разница между строкой (точнее,
std::string
) и символьным литералом заключается в том, что для последнего не+
определен оператор. Вот почему второй пример терпит неудачу.В первом случае компилятор может найти подходящий вариант
operator+
с первым аргументом, являющимся a,string
а вторым - символьным литералом (const char*
), поэтому он использовал это. Результатом этой операции снова будет astring
, поэтому он повторяет тот же трюк при добавлении"!"
к нему.источник