Михаил Гусаров - Вариации на тему STL. Адаптер обобщенного указателя на функцию-член класса
- Название:Вариации на тему STL. Адаптер обобщенного указателя на функцию-член класса
- Автор:
- Жанр:
- Издательство:неизвестно
- Год:неизвестен
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Михаил Гусаров - Вариации на тему STL. Адаптер обобщенного указателя на функцию-член класса краткое содержание
Вариации на тему STL. Адаптер обобщенного указателя на функцию-член класса - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
ПРИМЕЧАНИЕТаков, к примеру, 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 base;
};
};
template<> struct gen_mem_fun_traits {
template struct signature {
typedef void_gen_mem_fun_base_t base;
};
};
Этот класс специализирован для специального случая функции, возвращающей void. Таким образом, хоть нам и придется ввести дополнительный класс для функций, возвращающих void, для клиента это будет выглядеть единообразно: gen_mem_fun_traits::signature::base.
Сами по себе ветви вычислений различных вариантов тривиальны:
template
struct gen_mem_fun_base_t {
protected:
gen_mem_fun_base_t(R (T::*pm_)()): pm(pm_) {}
public:
template R operator()(TT p) {return (p.operator->()->*pm)();}
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 void operator()(TT p) {(p.operator->()->*pm)();}
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::template signature::base {
typedef gen_mem_fun_traits::template signature::base base_;
explicit gen_mem_fun_t(R (T::*pm_)()): base_(pm_) {}
};
Один момент здесь требует пояснения: typedef используется для того, чтобы компилятор понял, какому предку нужно передать в конструктор наш указатель на функцию-член.
И, наконец, gen_mem_fun вообще остался без изменений:
template
gen_mem_fun_t gen_mem_fun(R (T::*pm)()) {
return gen_mem_fun_t(pm);
}
Заключение
Надеюсь, читатель понял, что создание адаптера как такового не было основной целью этой статьи, тем более что гораздо более общий вариант такого адаптера под названием bind находится в библиотеке boost. Основная задача, которая стояла передо мной, была такова: дать читателю некоторые навыки и умения, позволяющие не пасовать перед необходимостью внести какие-либо дополнения или изменения в STL, а также познакомить с некоторыми приемами, специфичными для C++ и полезными при необходимости работать с компиляторами, не вполне поддерживающими стандарты.
Я благодарю Павла Кузнецова и Андрея Тарасевича за плодотворную дискуссию в форуме, непосредственно предшествовавшую написанию этой статьи и давшую мне некоторые приемы и идеи, которые были освещены выше.
Интервал:
Закладка: