Будет ли использование директивы препроцессора для определения того, что символ доллара представляет конфликт?

Могу ли я использовать следующее в C++?

#define $ cout

int main(){
    $<<"Hello World!\n";
    return 0;
}

Мне интересно, не вызовет ли это каких-либо конфликтов.

3 ответа

Решение

Это не совсем законно, но ваша реализация может принять это.

Рассматривать:

[C++11: 2.5/1]: Каждый токен предварительной обработки, который преобразуется в токен (2.7), должен иметь лексическую форму ключевого слова, идентификатора, литерала, оператора или пунктуатора.

Здесь ваш $ очевидно, не является ключевым словом, оператором или пунктуатором (так как они перечислены в стандарте), и не выглядит как литерал, так что это может быть только идентификатор; теперь идентификаторы должны содержать только буквенно-цифровые и подчеркивания, а цифры не могут быть начальными (на основе грамматики, обозначенной как [C++11: 2.11]).

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

Это поведение, определяемое реализацией. $ не входит в грамматику для идентификаторов, правила для имен идентификаторов в C++:

  1. Не может начинаться с цифры
  2. Может состоять из букв, цифр, подчеркивания, имен универсальных символов и символов, определенных для реализации
  3. Не может быть ключевым словом.

Но он допускает символы, определенные реализацией, которые многие компиляторы поддерживают как расширение, включая gcc и Visual Studio.

Фактическая грамматика описана в разделе стандарта C++. 2.11 Идентификатор:

identifier:
  identifier-nondigit            <- Can only start with a non-digit
  identifier identifier-nondigit <- Next two rules allows for subsequent 
  identifier digit               <-  characters to be those outlined in 2 above
identifier-nondigit:
  nondigit                       <- a-z, A-Z and _ 
  universal-character-name
  other implementation-defined characters
[...]

Мы можем видеть, что это относится к define из раздела 16 Директивы предварительной обработки. Из грамматики видно, что это должен быть идентификатор:

# define identifier replacement-list new-line
# define identifier lparen identifier-listopt) replacement-list new-line
# define identifier lparen ... ) replacement-list new-line
# define identifier lparen identifier-list, ... ) replacement-list new-line
         ^^^^^^^^^^

Забавная ситуация с некоторыми компиляторами, которые позволяют использовать $ в идентификаторах. Например как минимум MS VC++ 2010 позволяет использовать $ в идентификаторах.

Так что если, например, вы определили

char $ = '$';

а потом написал

#define $ std::cout
//...

$ << $;

тогда вместо символа $ вы увидите в консоли вывод № 1 или какое-то целое число.:)

Другие вопросы по тегам