Объединение двух строковых литералов
Я очень новичок в программировании и читаю "Ускоренный С++" от Koenig. В любом случае, я изучаю строки, и он пишет, что "новая идея заключается в том, что мы можем использовать + для конкатенации строки и строкового литерала - или, если на то пошло, две строки (но не две строковые литералы).
Хорошо, это имеет смысл, я полагаю. Теперь на два отдельных упражнения, предназначенных для освещения этого.
Имеются ли следующие определения?
const string hello = "Hello";
const string message = hello + ",world" + "!";
Теперь я попытался выполнить выше, и это сработало! Поэтому я был счастлив.
Затем я попытался выполнить следующее упражнение;
const string exclam = "!";
const string message = "Hello" + ",world" + exclam;
Это не сработало. Теперь я понимаю, что это связано с тем, что вы не можете конкатенировать два строковых литерала, но я не понимаю семантической разницы между тем, почему мне удалось получить первый пример для работы (это не "мир" и "!" Два строковых литерала? Не могли бы это не сработать?), но не второй.
Спасибо!
Ответы
Ответ 1
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
затем объединяется с "!"
.
Что касается того, почему вы не можете конкатенировать два строковых литерала с помощью +
, это потому, что строковый литерал - это просто массив символов (a const char [N]
где N
- длина строки плюс одна, для нулевой ограничитель). Когда вы используете массив в большинстве контекстов, он преобразуется в указатель на его исходный элемент.
Итак, когда вы пытаетесь сделать "Hello" + ",world"
, то, что вы действительно пытаетесь сделать, это добавить два const char*
вместе, что невозможно (что бы это означало добавить два указателя вместе?), и если это было бы не так, как вы этого хотели.
Обратите внимание, что вы можете конкатенировать строковые литералы, помещая их рядом друг с другом; например, следующие два эквивалентны:
"Hello" ",world"
"Hello,world"
Это полезно, если у вас длинный строковый литерал, который вы хотите разбить на несколько строк. Однако они должны быть строковыми литералами: это не будет работать с указателями const char*
или const char[N]
.
Ответ 2
Вы всегда должны обратить внимание на типы.
Хотя все они кажутся строками, "Hello"
и ",world"
являются литералами.
И в вашем примере exclam
является объектом std::string
.
С++ имеет перегрузку оператора, которая принимает объект std::string
и добавляет к нему другую строку. Когда вы объединяете объект std::string
с литералом, он сделает соответствующее литье для литерала.
Но если вы попытаетесь объединить два литерала, компилятор не сможет найти оператора, который принимает два литерала.
Ответ 3
Второй пример не работает, потому что для двух строковых литералов нет operator +
. Обратите внимание, что строковый литерал не имеет тип string
, но имеет тип const char *
. Ваш второй пример будет работать, если вы его отредактируете следующим образом:
const string message = string("Hello") + ",world" + exclam;
Ответ 4
В случае 1 из-за порядка операций вы получаете:
(hello + ", world" ) + "!" который решает привет + "!" и, наконец, приветствовать
В случае 2, как отметил Джеймс, вы получаете:
( "Hello" + ", world" ) + exclam, который является конкат двумя строковыми литералами.
Надеюсь, что это ясно:)
Ответ 5
Разница между строкой (или, если быть точнее, std::string
) и символьным литералом заключается в том, что для последнего не существует оператора +
. Вот почему второй пример терпит неудачу.
В первом случае компилятор может найти подходящий operator+
, причем первым аргументом является string
, а второй - символьный литерал (const char*
), поэтому он использовал это. Результатом этой операции снова является string
, поэтому он повторяет тот же трюк, добавляя к нему "!"
.