|
Программирование >> Обобщенные обратные вызовы
Metrowerks CodeWarrior 8 останавливался, сообщив о 52 ошибках (это не опечатка). 225 строк (это тоже не опечатка) сообщений об ошибках начинались со следующей диагностики, прямо указывающей на одну из запятых. ### гтмсс compiler: # File: 36.срр #-------------- # 17: enum uniontype {none, int, list, String}; # Error: л # identifier expected ### mwcc compiler: # 18: uniontype currtype; # Error: ЛЛЛЛЛЛЛЛЛ # declaration syntax error После этого следуют 52 сообщения об ошибках на еще 215 строках. Понятно, что вторую и дальнейшие ошибки можно просто игнорировать, так как эта лавина вызвана первой ошибкой - поскольку тип uniontype не был успешно определен, остаток текста, в котором он интенсивно используется, не может оказаться корректным с точки зрения компилятора. Но что же случилось с определением uniontype? Указанная запятая вроде бы находится на положенном месте? Перед ней находится нормальный идентификатор, все, как положено... Все становится понятным, если попросить компилятор Metrowerks вывести исходный текст после обработки препроиессором. Пропустив много-много строк, мы встретим следующую, которая и поступает на вход компилятора. enum uniontype {none, int, , }; Понятно, что это не корректный код С + + , и компилятор совершенно справедливо жалуется на третью запятую, поскольку перед ней нет никакого идентификатора. Но что же произошло с.....list и String? Можно предположить, что ими перекусил голодный зверь по кличке Препроцессор. Это произошло просто потому, что реализация Metrowerks определяет макрос, который при обработке препроцессором удалил имена list и string, что вполне законно, поскольку стандарт позволяет этой реализации определять собственные имена Names - как и other names. Итак, компилятор Metrowerks просто съел как LIST, так и string. Это объясняет первую часть чудес. А как насчет второй части - реализации EDGs/Dinkumware? Судите сами. 1.срр , 1iпе 17: error: trailing comma is nonstandard enum uniontype {NONE, INT, LIST, STRING}; l.cpp , line 58: error: expected an expression if С currtype== STRING) { l.cpp , line 63: error: expected an expression currtype= STRiNG; 1.срр , line 76: error: expected an expression case STRING: { л 4 errors detected in the compilation of Зб.срр . Что произошло в этот раз, можно понять даже без генерации исходного текста препроцессором и его проверки. Компилятор ведет себя так, как если бы слово string просто отсутствовало. Это связано с тем, что, как не сложно догадаться, оно тоже съедено все еще голодным Препроцессором. Я надеюсь, что эти при.меры убедили вас, что использовать в своих программах Имена наподобие этого не стоит и что данная проблема вовсе не так надуманна, как может показаться на первый взгляд. Как видите, это сугубо практическая проблема, поскольку ограничения на использование имен непосредственно влияют на ваши взаимоотношения с авторами компилятора и стандартной библиотеки. Не лезьте на их территорию, и вы останетесь невредимы. С++ достаточно открытый язык, который позволяет вам писать код любой степени сложности и гибкости, используя любые имена вне пространства имен std. Но все же, когда речь идет об именах, то у С++ в .этом отношении есть запретная зона, опутанная колючей проволокой и обставленная таблицами с надписями вход воспрещен, предъявите пропуск . Нарушителей - в зависимости от степени их невезения .......могут ждать крупные неприятности. > Рекомендация Никогда не используйте имена определенного вида, а именно - начинающиеся с подчеркивания и прописной буквы или содержащие двойное подчеркивание. Такие имена зарезервированы для использования компиляторами и реализациями стандартной библиотеки. Использование boost::any 4. Покажите лучший способ получения обобщенного вариантного типа, и расскажите, с какими сложностями вам пришлось столкнуться. В рассматриваемой статье сказано; Вы можете захотеть реализовать язык сценариев с единым типом переменных, которые могут быть целыми числами, строками ими списками. - [Мап1еу02] Все правильно и не вызывает никаких разногласий. Однако дальше сказано следующее: Объединение идеально подходит для реализации такого составного типа. - [Мап1еу02] Вместо этого статья служит демонстрацией того, почему объединения вообще не подходят для такой цели. Но если не объединения, то что же тогда следует использовать? Одним очень хорошим кандидатом для реализации такого вариантного типа является средство any из [Boost], вместе с many и anycast. Интересно, что полная реализация обобщенного any (работающего с любым количеством и любыми комбинациями типов, и даже с рядом платформозависимых #i fdef) имеет примерно такой же размер исходного текста, как и реализация myunion для рассмотренного частного случая трех типов i nt, list<int> и string, но при этом any представляет собой средство общего назначения, не зависящее от типов, расширяемое, безопасное с точки зрения типов, политкорректное и не содержащее холестерина. Естественно, и тут не обошлось без компромисса, который в данном случае представляет собой динамическое выделение памяти. Средство boost: :апу не пытается повысить эффективность за счет отказа от динамического распределения памяти, что было одним из исходных положений рассматриваемой статьи. Заметим также, что накладные расходы на динамическое распределение памяти в boost: :апу оказываются большими, чем в случае использования динамического выделения памяти для буфера в рассматриваемом нами фрагменте исходного текста. .Это связано с тем, что в случае MYUNION динамическое выделение памяти выполнялось бы однократно в течение жизни объекта, в то время как boost::any выполняет динамическое выделение памяти всякий раз при изменении типа своего содержимого. Вот как должна выглядеть демонстрационная часть исходного текста из статьи при использовании boost: :апу вместо myunion (оригинальный код статьи приведен в качестве комментария). Более детальное рассмотрение этого вопроса имеется в [HyslopO!]. 238 Изучение конкретных примеров any u; Вместо: myunion u; Вместо самодельной структуры, которая должна разрабатываться отдельно для каждого конкретного случая, здесь использован класс any. Заметим, что это обычный класс, а не шаблон. Обращение к объединению как к int u = 12345; вместо: u.getintC) = 12345; Это присваивание any имеет более естественный синтаксис. cout int= any cast<int>(u) endl; или просто int(u) Вместо: cout int= u.getintC) endl; Преобразование типа any мне представляется предпочтительным в силу его большей обобшенности (включая то, что не используется синтаксис доступа к члену класса) и большего соответствия естественному стилю С++; можно также воспользоваться более кратким int (и), без any cast, если тип вам известен. Кроме того, функции MYUNION get type менее надежны, сложны в написании, сопровождении и т.д. Обращение к объединению как к std::list u = list<int>C); list<int>& 1 = *any cast<list<int> >C&u); вместо: LIST& list = u.getlistO; 1.push back(5); Аналогично: 1ist.push backC5); 1.push backC10); Аналогично: list.pushbackCIO); 1.push back(15); Аналогично: 1ist.push backC15); Я думаю, что any cast можно усовершенствовать, с тем чтобы ссылку можно было получить более простым способом. (Кстати: мне не нравится использование 1 i st в качестве имени переменной, когда в области видимости оказывается шаблон с тем же именем; это дает слишком много возможностей для неоднозначности.) Итак, мы достигли большей удобочитасмости и типизирусмости. Остальные отличия не так уж велики. list<int>: :iterator it = 1.beginO; Вместо: list::iterator it = list.begin О; whileC it != 1 .endO ) { cout list item= *Cit) endl; it++; } while Почти так же, как и в оригинале. Продолжим сравнение. Обращение к объединению как к std::string u = stringC Hello world! ); Вместо: STRING& str = u.getstringO; str = Hello world! ; Опять версия с any немного проще исходной, но всего лишь немного. cout string= any cast<string>Cu) или просто stringCu) endl; Вместо: cout string= str.c strC) endl; Размеченные объединения Александреску Нельзя ли достичь обеих поставленных целей ~ безопасности и отказа от динамического распределения памяти - при полном соответствии стандарту? Это похоже на проблемы, которые так любит Андрей Александреску (Andrei Alexandrescu), особенно если при этом можно написать шаблоны посложнее. Как видно из [Alexandrescu02], где он описал свои подход к объединениям (variant), это возможно, причем с использованием шабло-нов (думали ли вы, rтo объединения могут быть шаблонами?), и это сделано.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |