|
Программирование >> Обобщенные обратные вызовы
Задача 33. Ооооператоры Сложность: 4 Сколько операторов можно поместить подряд так, чтобы это имело смысл ? В определенном смысле эту задачу можно считать шуткой. Вопрос для новичка 1. Какое наибольшее количество плюсов (+) могут быть расположены подряд, без включения пробельных символов, в корректной программе на С++? Примечание: конечно, плюсы в комментариях, директивах препроцессора, макросах и литералах не учитываются. Это было бы неспортивно. Вопрос для профессионала 2. Аналогично, чему равно наибольшее количество каждых из приведенных далее символов, которые могут располагаться в программе подряд, без вставки пробельных символов, вне комментариев в корректной программе на С++? а) & б) < в) I Например, для пункта а) код if(a&&b) демонстрирует тривиальный случай двух п осл с до вате л ь и ы х символов & в корректной программе на С++. Попробуйте найти примеры с большим количеством символов. Решение Правило максимального глотка Правило максимального глотка гласит, что при разбивке символов исходного текста на лексемы компилятор должен поступать в соответствии с жадным алгоритмом -- т.е. выбирать наиболее длинную из возможных лексем. Таким образом, всегда интерпретируется как единая лексема -- оператор извлечения из потока (или битового сдвига вправо), и никогда - как две отдельные лексемы >, даже в ситуации наподобие следующей: tempi ate<cl ass т = x<Y Вот почему такой код следует писать с дополнительным пробелом: tempiate<class т = x<Y> > Аналогично, > всегда интерпретируется как с последующим за ним >, но не как > с последующим . Операторные шутки 1. Какое наибольшее количество плюсов (+) могут быть расположены подряд, без включения пробельных си.мволов, в корректной программе на С++? Примечание: конечно, плюсы в комментариях, директивах препроцессора, макросах и литералах не учитываются. Это было бы неспортивно. Можно создать исходный файл, содержащий последовательность символов + произвольной длины (ограниченной возможностями компилятора по обработке длинной строки). Если последовательность состоит из четного количества символов +, она интерпретируется как ++ ++++++ ... ++, т.е. как последовательность двухсимвольных лексем ++. Для того чтобы такой код был работоспособен и имел однозначно определенную семантику, все, что нам надо, - это класс, в котором определен пользовательский префиксный оператор ++, обеспечивающий возможность цепочечного вызова. Например: пример 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&&( &А::operators*, &а ); Теперь разберемся с оставшимися символами: а) < б) I В обоих случаях ответ один - четыре. Имея решение вопроса 2а, не сложно расправиться и с оставшимися двумя. Чтобы получить последовательность из четырех символов, воспользуемся тем же трюком, что и ранее, и определим void operator ( F, А ) { } void operator I( F, a ) { } Это позволит нам написать &А: :operater a; &А::operator I!a; MM что означает operater ( &A: :eperater , a ) ; operator!( &A::eperaterM, a );
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |