it-swarm.com.ru

Объединить два строковых литерала

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

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

Являются ли следующие определения действительными?

const string hello = "Hello";

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

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

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

const string exclam = "!";

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

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

111
Arthur Collé
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*s вместе, что невозможно (что бы это значило, если добавить два указателя вместе?), И если бы это было так, это не сделало бы то, что Вы хотели это сделать.


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

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

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

131
James McNellis

Вы всегда должны обращать внимание на типы.

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

И в вашем примере exclam является объектом std::string.

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

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

8
Yochai Timmer

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

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

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

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

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

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

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

2
Stephen

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

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

1
Péter Török