C++ многострочный строковый литерал


есть ли способ иметь многострочный простой текст, постоянные литералы в C++, à la Perl? Может быть, какой-то парсинг трюк с #includeing файл? Я не могу придумать ни одного, но это было бы здорово. Я знаю, что это будет в C++0x.

7 327

7 ответов:

хорошо ... Что-то вроде того. Проще всего просто использовать тот факт, что соседние строковые литералы объединяются компилятором:

const char *text =
  "This text is pretty long, but will be "
  "concatenated into just a single string. "
  "The disadvantage is that you have to quote "
  "each part, and newlines must be literal as "
  "usual.";

отступ не имеет значения, так как он не находится внутри кавычек.

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

const char *text2 =
  "Here, on the other hand, I've gone crazy \
and really let the literal span several lines, \
without bothering with quoting each line's \
content. This works, but you can't indent.";

опять же, обратите внимание на эти обратные косые черты в конце каждой строки, они должны быть непосредственно перед строка заканчивается, они избегают новой строки в источнике, так что все действует так, как будто новой строки там не было. Вы не получаете новые строки в строке в местах, где у вас были обратные косые черты. С помощью этой формы вы, очевидно, не можете отступить текст, так как отступ станет частью строки, искажая ее случайными пробелами.

В C++11 у вас есть "сырые" строковые литералы. Вроде как здесь-текст в оболочках и скриптовых языках, таких как Python и Perl и Ruby.

const char * vogon_poem = R"V0G0N(
             O freddled gruntbuggly thy micturations are to me
                 As plured gabbleblochits on a lurgid bee.
              Groop, I implore thee my foonting turlingdromes.   
           And hooptiously drangle me with crinkly bindlewurdles,
Or I will rend thee in the gobberwarts with my blurlecruncheon, see if I don't.

                (by Prostetnic Vogon Jeltz; see p. 56/57)
)V0G0N";

все пробелы и отступы и новые строки в строке сохраняются.

Они также могут быть UTF-8/16/32 или wchar_t (с обычными префиксами).

Я должен отметить, что escape-последовательность, V0G0N, на самом деле не нужна здесь. Его наличие позволит поставить ) " внутри строки. Другими словами, Я мог бы поставить

                "(by Prostetnic Vogon Jeltz; see p. 56/57)"

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

const char * vogon_poem = R"( ... )";

парены только внутри кавычек по-прежнему необходимы.

#define MULTILINE(...) #__VA_ARGS__
Потребляет все между скобками.
Заменяет любое количество последовательных пробелов одним пробелом.

Это, наверное, удобный способ ввода нескольких строк с помощью макроса. Это работает только если кавычки и скобки сбалансированы и не содержат 'верхнем уровне' запятой:

#define MULTI_LINE_STRING(a) #a
const char *text = MULTI_LINE_STRING(
  Using this trick(,) you don't need to use quotes.
  Though newlines and     multiple     white   spaces
  will be replaced by a single whitespace.
);
printf("[[%s]]\n",text);

скомпилированный с gcc 4.6 или g++ 4.6, это производит:[[Using this trick(,) you don't need to use quotes. Though newlines and multiple white spaces will be replaced by a single whitespace.]]

отметим, что , не может быть в строке, если она не содержится в скобках или кавычках. Одинарные кавычки возможны, но создает предупреждения компилятора.

Edit: как упоминается в комментариях,#define MULTI_LINE_STRING(...) #__VA_ARGS__ позволяет использовать ,.

вы можете просто сделать это:

const char *text = "This is my string it is "
     "very long";

поскольку унция опыта стоит тонны теории, я попробовал небольшую тестовую программу для MULTILINE:

#define MULTILINE(...) #__VA_ARGS__

const char *mstr[] =
{
    MULTILINE(1, 2, 3),       // "1, 2, 3"
    MULTILINE(1,2,3),         // "1,2,3"
    MULTILINE(1 , 2 , 3),     // "1 , 2 , 3"
    MULTILINE( 1 , 2 , 3 ),   // "1 , 2 , 3"
    MULTILINE((1,  2,  3)),   // "(1,  2,  3)"
    MULTILINE(1
              2
              3),             // "1 2 3"
    MULTILINE(1\n2\n3\n),     // "1\n2\n3\n"
    MULTILINE(1\n
              2\n
              3\n),           // "1\n 2\n 3\n"
    MULTILINE(1, "2" )      // "1, \"2\" "
};

скомпилировать этот фрагмент cpp -P -std=c++11 filename воспроизвести.

секрет #__VA_ARGS__ это __VA_ARGS__ не обрабатывает запятая. Так что вы можете передать его в строковый оператор. Начальные и конечные пробелы обрезаются, а пробелы (включая новые строки) между словами сжимаются до одного пробела. Скобки должны быть сбалансированы. Я думаю эти недостатки объясняют, почему конструкторы C++11, несмотря на #__VA_ARGS__, увидел необходимость в необработанных строковых литералах.

просто чтобы немного прояснить комментарий @emsr в ответе @unwind, если вам не повезло иметь компилятор C++11 (скажем, GCC 4.2.1), и вы хотите встроить новые строки в строку (либо char*, либо строку класса), можно написать что-то вроде этого:

const char *text =
  "This text is pretty long, but will be\n"
  "concatenated into just a single string.\n"
  "The disadvantage is that you have to quote\n"
  "each part, and newlines must be literal as\n"
  "usual.";

очень очевидно, правда, но короткий комментарий @emsr не выскочил на меня, когда я прочитал это в первый раз, поэтому мне пришлось открыть это для себя. Надеюсь, я сэкономил кому-то еще несколько минут.