Почему я могу построить строку с несколькими строковыми литералами?

#include <iostream>
#include <string>

int main() {
    std::string str = "hello " "world" "!";
    std::cout << str;
}

Следующее компилируется, запускается и печатается:

Привет мир!

посмотреть в прямом эфире


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

#include <iostream>
#include <string>

int main() {
    std::string str = "hello " + "world";
    std::cout << str;
}

Это не скомпилируется.
посмотреть вживую


Почему такое поведение в языке? Моя теория заключается в том, что это позволяет создавать строки с несколькими операторами #include, потому что операторы #include должны находиться на отдельной строке. Возможно ли такое поведение просто из-за грамматики языка, или это исключение, которое было добавлено, чтобы помочь решить проблему?


person Trevor Hickey    schedule 07.02.2014    source источник
comment
Ошибка говорит обо всем, не так ли?   -  person P0W    schedule 07.02.2014
comment
Потому что это C/C++, а не Java.   -  person devnull    schedule 07.02.2014
comment
@devnull дубликат охватывает только половину вопросов вопроса, вопрос также о том, почему строковый литерал + строковый литерал не работает, что не охватывается дублированием.   -  person Shafik Yaghmour    schedule 07.02.2014


Ответы (5)


Смежные строковые литералы объединены, мы можем видеть это в черновик стандарта C++, раздел 2.2 Фазы перевода, пункт 6, в котором говорится:

Смежные токены строкового литерала объединяются

В другом случае не существует operator+, определенного для принятия два *const char**.

Почему это происходит из C, и мы можем перейти к Обоснование международного стандарта — Языки программирования — C, а в разделе 6.4.5 Строковые литералы говорится:

Строка может быть продолжена на несколько строк с помощью продолжения строки с обратной косой чертой и новой строки, но для этого требуется, чтобы продолжение строки начиналось с первой позиции следующей строки. Чтобы обеспечить более гибкую компоновку и решить некоторые проблемы предварительной обработки (см. §6.10.3), комитет C89 ввел конкатенацию строковых литералов. Два строковых литерала в строке вставляются вместе без нулевого символа в середине, чтобы получился один комбинированный строковый литерал. Это дополнение к языку C позволяет программисту расширить строковый литерал за конец физической строки без использования механизма обратной косой черты и новой строки и тем самым разрушить схему отступов программы. Явный оператор конкатенации не был введен, потому что конкатенация является лексической конструкцией, а не операцией времени выполнения.

без этой функции вам пришлось бы сделать это, чтобы продолжить строковый литерал на несколько строк:

   std::string str = "hello \
world\
!";

что довольно некрасиво.

person Shafik Yaghmour    schedule 07.02.2014

Как сказал @erenon, компилятор объединит несколько строковых литералов в один, что особенно полезно, если вы хотите использовать несколько строк, например:

cout << "This is a very long string-literal, "
        "which for readability in the code "
        "is divided over multiple lines.";

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

string str = string("Hello ") + "world";
person JorenHeit    schedule 07.02.2014

Компилятор автоматически объединяет строковые литералы в один.

person erenon    schedule 07.02.2014

Когда компилятор видит, что "hello " + "world"; ищет глобальный оператор +, который принимает два const char* ... И поскольку по умолчанию его нет, он терпит неудачу.

Компилятор разрешает "hello " "world" "!" как одну строку. Это позволяет вам иметь конкатенированные строки, записанные на нескольких строках.

person Ferenc Deak    schedule 07.02.2014

В первом примере последовательные строковые литералы объединяются по волшебству до того, как компиляция начнется должным образом. Компилятор видит один литерал, как если бы вы написали "hello world!".

Во втором примере после начала компиляции литералы становятся статическими массивами. Вы не можете применить + к двум массивам.

Почему такое поведение в языке?

Это наследие языка C, унаследованное от тех времен, когда память была ценным ресурсом. Это позволяет вам выполнять довольно много манипуляций со строками, не требуя динамического выделения памяти (как часто делают более современные идиомы, такие как std::string); цена за это - довольно причудливая семантика.

person Mike Seymour    schedule 07.02.2014