Я выполнил следующий код через препроцессор Visual Studio 2013. Результат меня удивляет.
Содержимое hello.cpp:
#define A(j) #j
A(A?)
A(B?)
A(C?)
A(D?)
A(E?)
A(F?)
A(G?)
A(H?)
A(I?)
A(J?)
A(K?)
A(L?)
A(M?)
A(N?)
A(O?)
A(P?)
A(Q?)
A(R?)
A(S?)
A(T?)
A(U?)
A(V?)
A(W?)
A(X?)
A(Y?)
A(Z?)
Команда:
cl /P hello.cpp
hello.i содержит:
#line 1 "hello.cpp""A?""B?""C?""D?""E?""F?""G?""H?""I?""J?""K?""L""M?""N?""O?""P?""Q?""R""S?""T?""U?""V?""W?""X?""Y?""Z?"
Я столкнулся с этим, пытаясь вызвать A (L? P: q), что привело к «Lp: q», что мне не подходит.
Это правильный, четко определенный C ++? Что особенного в L и R в C ++? Если файл имеет расширение .c, L и R обрабатываются идентично остальной части алфавита. Это связано с C ++ 11? Это должно быть новая функция, так как более старые версии MSVS не используют L и R особым образом.
И что я могу сделать, чтобы MSVS 2013 не обрабатывал L и R таким особым образом?
Обновить
Похоже, отчет об ошибке был помечен как дубликат этот который имеет обновление, которое говорит:
Исправление для этой проблемы было проверено в источниках компилятора. Исправление должно появиться в следующем основном выпуске Visual C ++.
оригинал
Как отметил Ремябель, это сообщенная ошибка. ни gcc
ни clang
произвести эти результаты и строковый оператор # в соответствии с Visual Studios
документы, это следующие замены (Акцент шахты идет вперед):
Пробел, предшествующий первому токену фактического аргумента и следующий за последним токеном фактического аргумента, игнорируется. Любой пробел между токенами в фактическом аргументе уменьшается до одного пробела в результирующем строковом литерале. Таким образом, если комментарий присутствует между двумя токенами в фактическом аргументе, он уменьшается до одного пробела. Результирующий строковый литерал автоматически объединяется с любыми соседними строковыми литералами, от которых он отделяется только пробелом.
Кроме того, если символ, содержащийся в аргументе, обычно требует escape-последовательности при использовании в строковом литерале (например, кавычка («) или символ обратной косой черты ()), необходимая обратная косая черта автоматически вставляется перед символом.
что соответствует Проект стандарта C ++ раздел 16.3.2
Оператор который говорит:
Если в списке замены параметру сразу предшествует # токен предварительной обработки, оба заменяются токеном предварительной обработки литеральной строки, состоящим из одной строки символов, который содержит написание последовательности токена предварительной обработки для соответствующего
аргумент. Каждое вхождение пробела между токенами предварительной обработки аргумента становится одним пробелом в строковом литерале. Пробелы перед первым токеном предварительной обработки и после последнего токена предварительной обработки, содержащего аргумент, удаляются. В противном случае исходное написание каждого токена предварительной обработки в аргументе сохраняется в строковом литерале символов, за исключением специальной обработки для создания правописания строковых литералов и символьных литералов: символы \ вставляются перед каждым знаком «и \ символа литерала символа». или строковый литерал (включая символы-разделители).
Единственное, что относится R
а также L
в отношении C ++ 11 является то, что они имеют особое значение с строковые литералы но я не понимаю, как это должно повлиять на этот случай.
Это также выглядит как L\
а также R\
также производят ту же проблему.
Они делают документ один несоответствующий вопрос и это говорит:
Visual C ++ не работает правильно, когда оператор # (stringize) используется со строками, которые содержат escape-последовательности. В этой ситуации компилятор сгенерирует ошибку компилятора C2017.
который не охватывает этот случай.
Это похоже на ошибку в препроцессоре MSVC. Хорошей новостью является то, что в зависимости от того, насколько вы разборчивы в своем выводе, вы можете обойти эту проблему, поставив пробел после R или L.
A(L ?p:q), // "L ?p:q"