Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 [ 64 ] 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85

лексем ++. Для того чтобы такой код был работоспособен и имел однозначно определенную семантику, все, что нам надо, - это класс, в котором определен пользовательский префиксный оператор ++, обеспечивающий возможность цепочечного вызова. Например:

пример 33-1(а)

class А { public:

А& operator++C) { return *this; }

Теперь мы можем записать код А а;

++++++а; Означает: ++ ++ ++ а;

который работает следующим образом

a.operator++().operator++().operator++C)

А что, если последовательность имеет нечетное число символов +? Тогда она интерпретируется как ++ ++++++ ... ++ +, последовательность двухсимвольных лексем ++, за которой следует заключающий символ +. Для того чтобы такой код был работоспособен, надо дополнительно определить унарный оператор +.

пример 33-1(6)

class А { public:

А& operator+ () { return *this; } A& operator++0 { return *this; }

Теперь мы можем записать код А а;

+++++++а; означает: +++++++ а; который работает следующим образом.

a.operator+O.operator++C).operator++C).operator++()

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

Злоупотребление операторами

Код в примерах 33-1а и 33-16 не слишком злоупотребляет обычной семантикой операторов ++ и +. В дальнейшей работе, однако, нам придется далеко отойти от общепринятых правил кодирования. То, что вы увидите дальше, - не для промышленного использования, а всего лишь для собственного удовольствия.

2. Аналогично, чему равно наибольшее количество каждых из приведенных далее символов, которые могут располагаться в программе подряд, без вставки пробельных символов, вне комментариев в корректной программе иа С++?

Для ответа на этот вопрос мы создадим вспомогательный класс Пример 33-2

class А { public:

void operator&&( int ) { }

void operator«( int ) { }

void operator I( int ) { }



typedef void (A::*F)(int);

Теперь начнем с рассмотрения символа

а) &

Ответ: пять.

Ну, && - это просто; не сложно и &&&. Так что пойдем сразу дальше. Можем ли мы создать последовательность из четырех символов &&&&? Если да, то она должна интерпретироваться как && &&, но выражение наподобие а && && b синтаксически некорректно; мы не можем разместить два бинарных оператора один за другим.

Трюк заключается в том, что мы можем использовать вторую пару && как оператор, сделав первую пару && окончанием чего-то, что оператором не является. В таком случае требуется не так много времени, чтобы увидеть, что первая пара && может быть окончанием имени, а именно - имени функции, так что все, что нам нужно, - оператор operator&&(), который может получать указатель на некоторый другой оператор operateг&&() в качестве первого параметра:

void operator&&( F, А ) { }

Это позволяет нам записать

&А::operateг&&&&а; &&&& что означает

operator&&( &А::operateг&&, а );

Это самая длинная последовательность из четного количества символов &, поскольку &&&&&& - некорректная запись. Почему? Потому что она означает && && &&, но даже делая первую пару && частью имени, мы не можем сделать последнюю пару && началом другого имени; остается только разместить два бинарных оператора && подряд, что невозможно.

Но не можем ли мы добавить еще один символ &, чгобы получить нечетное количество символов & в последовательности? Конечно, можем. Конкретно - &&&&& означает &&&&&; для первой части решение у нас уже есть, так что не надо долго думать, чтобы суметь прицепить к нему унарный оператор &.

&А::operateг&&&&&а; &&&&& что означает

operator&&( &А::operateг&&, &а ); Теперь разберемся с оставшимися символами:

а) <

б) I

В обоих случаях ответ один - четыре.

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

void operator«( F, А ) { } void operator I( F, A ) { }

Это позволит нам написать

&А: :operateг««а; « « &А::operator]!а; II И

что означает

operater«( &А: :eperater«, а ) ; operatorI( &А::eperaterl, а );



Это самые длинные последовательности, которые мы можем получить, потому что ««« и I I { I I I должны быть некорректны исходя из тех же рассуждений, которые мы применяли к последовательности М&&&&. Но в этот раз мы не можем добавить дополнительные символы < или I, чтобы получить последовательности из пяти символов, поскольку унарные операторы < и не существуют.

Дополнительный вопрос

А сколько вопросительных знаков (?) вы сможете разместить подряд в строке программы на С++?

Подумайте немного над этим вопросом, прежде чем читать дальше. Этот вопрос сложнее, чем кажется на первый взгляд.

Есть ли у вас ответ?

Вы можете решить, что ответ - один, поскольку в С++ имеется только одна допустимая лексема, включающая вопросительный знак - тернарный оператор ?:. Да, есть только одно средство в языке, которое использует вопросительный знак, но "есть много, друг Горацио, вещей в трансляторах и препроцессорах, которые и не снились синтаксическим правилам..." В частности, помимо прочего, С++ это еще и препроцессор, а не только язык.

Для символа ? правильный ответ - три. Например:

1???-0:0;

Этот вопрос труднее в первую очередь потому, что он нарушает правило максимального глотка. Три вопросительных знака ??? не интерпретируются как лексемы ?? и ?. Почему? Потому что "??-" - это триграф, а триграфы обрабатываются до лексического разбора, и даже до обработки директив препроцессора. Если до этого вы не слышали о триграфах - не волнуйтесь, это всего лишь означает, что вы никогда не имели дело с экзотическими клавиатурами и не читали задачу 32. Триграф - это альтернативный способ ввода некоторых символов в исходном тексте (в частности, #, \, л, [> ], I, {, } и ~) на клавиатурах, которые не имеют клавиш для данных символов.

В нашем случае задолго до лексического анализа триграф ??- заменяется символом ~, оператором побитового отрицания. Таким образом, исходный текст превращается в следующий:

1?~0:0;

который при лексическом анализе разбивается на лексемы

1 ? ~ О : О ; и означает

1 ? (~0) : О ;

Резюме

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



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 [ 64 ] 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85