Quelle est la particularité de R et L dans le préprocesseur C ++?

J’ai exécuté le code suivant via le préprocesseur Visual Studio 2013. La sortie me surprend.

Contenu de 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?) 

La commande:

 cl /P hello.cpp 

bonjour.i contient:

 #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?" 

J’ai couru en essayant d’appeler A (L? P: q), ce qui a abouti à “Lp: q”, ce qui n’est pas bon pour moi.

Est-ce que C ++ est bien défini? Quelle est la particularité de L et R en C ++? Si le fichier a l’extension .c, L et R sont traités de la même manière que le rest de l’alphabet. Est-ce lié à C ++ 11? Ce doit être une nouvelle fonctionnalité, car les anciennes versions de MSVS ne prennent pas en charge les versions L et R.

Et que puis-je faire pour empêcher MSVS 2013 de traiter L et R de cette manière particulière?

Mettre à jour

On dirait que le rapport de bogue a été marqué comme un duplicata de celui-ci qui a une mise à jour qui dit:

Un correctif pour ce problème a été vérifié dans les sources du compilateur. Le correctif devrait apparaître dans la prochaine version majeure de Visual C ++.

Original

Comme le soulignait remyabel, ceci est un bogue signalé . Ni gcc ni clang produisent ces résultats et l’ opérateur de ssortingngizing # selon Visual Studios documents Visual Studios , ce sont les remplacements suivants ( accent mis sur le futur ):

L’espace blanc précédant le premier jeton de l’argument réel et suivant le dernier jeton de l’argument réel est ignoré. Tout espace blanc entre les jetons dans l’argument réel est réduit à un seul espace blanc dans le littéral de chaîne résultant. Ainsi, si un commentaire se produit entre deux jetons dans l’argument réel, il est réduit à un seul espace blanc. Le littéral de chaîne résultant est automatiquement concaténé avec tous les littéraux de chaîne adjacents à partir desquels il n’est séparé que par un espace blanc.

De plus, si un caractère contenu dans l’argument nécessite généralement une séquence d’échappement lorsqu’il est utilisé dans un littéral de chaîne (par exemple, le guillemet (“) ou la barre oblique inverse ()), la barre oblique inverse nécessaire est automatiquement insérée avant le caractère.

ce qui correspond à l’ ébauche de norme C ++ section 16.3.2 L’opérateur # qui dit:

Si, dans la liste de remplacement, un paramètre est immédiatement précédé par un jeton de prétraitement #, les deux sont remplacés par un jeton de prétraitement littéral de chaîne de caractères unique contenant l’orthographe de la séquence de jeton de prétraitement pour l’argument correspondant. Chaque occurrence d’espace blanc entre les jetons de prétraitement de l’argument devient un caractère d’espace unique dans le littéral de chaîne de caractères. L’espace blanc avant le premier jeton de prétraitement et après le dernier jeton de prétraitement comprenant l’argument est supprimé. Sinon, l’orthographe d’origine de chaque jeton de prétraitement dans l’argument est conservée dans le littéral de la chaîne de caractères, sauf en ce qui concerne l’orthographe des littéraux de chaîne et des caractères: un caractère \ est inséré avant chaque caractère et un caractère littéral ou chaîne littérale (y compris les caractères de délimitation).

La seule chose qui relie R et L à C ++ 11 est qu’ils ont une signification particulière avec les littéraux de chaîne, mais je ne vois pas comment cela devrait affecter ce cas.

Il semble également que L\ et R\ produisent également le même problème.

Ils documentent un problème non conforme et disent:

Visual C ++ ne se comporte pas correctement lorsque l’opérateur # (ssortingngize) est utilisé avec des chaînes contenant des séquences d’échappement. Dans cette situation, le compilateur générera une erreur de compilation C2017.

qui ne couvre pas ce cas.

Cela semble être un bogue dans le préprocesseur MSVC. La bonne nouvelle est que, selon votre degré de précision avec votre sortie, vous pouvez contourner le problème en mettant un espace après le R ou le L.

 A(L ?p:q), // "L ?p:q"