Законно ли переопределять ключевые слова C ++, если я не включаю один заголовок? - PullRequest
3 голосов
/ 09 ноября 2019

Рассмотрим этот код:

#define private public

struct Test {
    private:
    int s{9};
};

int main() { }

Я уже прошел через это и это . Я не включил один заголовок здесь. Означает ли это, что поведение программы хорошо определено или все еще определяется в соответствии со стандартом C ++?

1 Ответ

1 голос
/ 09 ноября 2019

Хотя это, безусловно, будет «работать», и вам в значительной степени гарантировано, что «настоящий» UB не вызывается, но я думаю, что на букву стандарта, можно утверждать, что Undefined Behavior вызываетсяВ соответствии с длительными и несколько неоднозначными разработками [lex].

Точно так же нет никакого "реального вреда" в совершении чего-то вроде #define __included_foo_h или struct bar { int _Data; };, но стандарт прямо говорит в [lex.name] что эти имена зарезервированы. Что, как ни крути, это именно то, что есть.

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

В частности:

[lex.key]
Идентификаторы, показанные в таблице 5, зарезервированы для использования в качестве ключевых слов (то естьони безусловно обрабатываются как ключевые слова в фазе 7), за исключением токена атрибута

[lex.phases]
7. Символы пробела, разделяющие токены, более не имеют значения. Каждый токен предварительной обработки преобразуется в токен. Полученные токены синтаксически и семантически анализируются и переводятся как единица перевода.

Правда, в фазе 4 происходят макро-замены, поэтому фаза 7 не будет "видеть" переопределенное ключевое слово как таковое. Тем не менее, он четко говорит «зарезервировано» и «безусловно». Итак, если вам было позволено просто игнорировать это на основе «но компилятор не видит», то вы могли бы, например, #define __inline inline [[gnu:always_inline]] с той же логикой. Кому интересно, если зарезервированы двойные подчеркивания, компилятор этого не видит!

Не думаю, что, хотя это, безусловно, будет «работать», это строго законная точка зрения.

(Забавный факт: я однажды использовал #define private public, работал как шарм.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...