Вариации на тему STL. Адаптер обобщенного указателя на функцию-член класса - [2]
>template
>gen_mem_fun_t
> return gen_mem_fun_t
>}
Проблемы с разными компиляторами
Специализация шаблонных функций – членов шаблонного класса
К сожалению, вышеприведенный код не будет компилироваться на компиляторах, не поддерживающих специализацию шаблонов-функций – членов шаблонов классов.
ПРИМЕЧАНИЕ К таким относятся, например, gcc-2.95 и gcc-2.96
Попробуем обойтись без них. Специализация в той или иной форме нам в любом случае понадобится, так что воспользуемся тем, что есть – частичной специализацией классов. Введем вспомогательный класс и специализируем его для особого случая обычных указателей.
>template
>struct gen_mem_fun_operator {
> R operator()(TT p, R (T::*pm)()) {return (p.operator->()->*pm)();}
>};
>template
>struct gen_mem_fun_operator
> R operator()(T* p, R (T::*pm)()) {return (p->*pm)();}
>};
Тогда наш gen_mem_fun_t запишется так:
>tem
>pl
ate
>struct gen_mem_fun_t {
> explicit gen_mem_fun_t(R (T::*pm_)()): pm(pm_) {}
> template
>private:
> R (T::*pm)();
>};
Проблема “return void”
Посмотрим внимательнее на реализацию функции operator() в нашем адаптере. Что будет, если мы захотим в качестве типа возвращаемого значения функции использовать void? Наша функция запишется так: void operator() {return void;}. С точки зрения стандарта все хорошо, но все в нашем мире определяется стандартом: есть компиляторы, которые не воспринимают такую конструкцию как допустимую.
ПРИМЕЧАНИЕ Таков, к примеру, Microsoft Visual C++ 6.0/7.0
К счастью, на помощь нам опять приходит частичная специализация:
>template
>struct gen_mem_fun_operator
> void operator()(TT p, void (T::*pm)()) {(p.operator->()->*pm)();}
>};
>template
>struct gen_mem_fun_operator
> void operator()(T* p, void (T::*pm)()) {(p->*pm)();}
>};
Частичная специализация
К сожалению, не все компиляторы поддерживают частичную специализацию шаблонных классов.
ПРИМЕЧАНИЕ К таким относится и Microsoft Visual C++ 6.0/7.0
Для решения этой проблемы можно использовать паттерн «traits», специфичный для C++. К сожалению, он не сможет помочь в случае, когда один из параметров шаблона специализируется типом, зависящим от другого параметра шаблона, но в случае проблемы «return void» он помочь сможет.
ПРИМЕЧАНИЕ Вопрос, реально ли вообще симулировать частичную специализацию шаблонов, где специализируемый параметр шаблона зависит от неспециализируемого, на компиляторе, не поддерживающем частичную специализацию шаблонов и поддерживающем специализацию вообще только для глобальных классов и функций, остается открытым. Я такой возможности не вижу. Таким образом, создать без помощи препроцессора код нашего адаптера, компилирующийся и под gcc и под Visual C++, не представляется возможным.
Введем вспомогательный класс
>template
>struct gen_mem_fun_traits {
> template
> struct signature {
> typedef gen_mem_fun_base_t
> };
>};
>template<> struct gen_mem_fun_traits
> template
> typedef void_gen_mem_fun_base_t
> };
>};
Этот класс специализирован для специального случая функции, возвращающей void. Таким образом, хоть нам и придется ввести дополнительный класс для функций, возвращающих void, для клиента это будет выглядеть единообразно: gen_mem_fun_traits
Сами по себе ветви вычислений различных вариантов тривиальны:
>template
>struct gen_mem_fun_base_t {
>protected:
> gen_mem_fun_base_t(R (T::*pm_)()): pm(pm_) {}
>public:
> template
> template<> R operator()(T* p) {return (p->*pm)();}
>private:
> R (T::*pm)();
>};
>template
>struct void_gen_mem_fun_base_t {
>protected:
> void_gen_mem_fun_base_t(void (T::*pm_)()): pm(pm_) {}
>public:
> template
> template<> void operator()(T* p) {(p->*pm)();}
>private:
> void (T::*pm)();
>};
Теперь определим сам gen_mem_fun_t:
>template
>struct gen_mem_fun_t: gen_mem_fun_traits
> typedef gen_mem_fun_traits
> explicit gen_mem_fun_t(R (T::*pm_)()): base_(pm_) {}
>};
Один момент здесь требует пояснения: typedef используется для того, чтобы компилятор понял, какому предку нужно передать в конструктор наш указатель на функцию-член.
И, наконец, gen_mem_fun вообще остался без изменений:
>template
>gen_mem_fun_t
> return gen_mem_fun_t
>}
Заключение
Надеюсь, читатель понял, что создание адаптера как такового не было основной целью этой статьи, тем более что гораздо более общий вариант такого адаптера под названием bind находится в библиотеке boost. Основная задача, которая стояла передо мной, была такова: дать читателю некоторые навыки и умения, позволяющие не пасовать перед необходимостью внести какие-либо дополнения или изменения в STL, а также познакомить с некоторыми приемами, специфичными для C++ и полезными при необходимости работать с компиляторами, не вполне поддерживающими стандарты.
Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.
Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.