Чтение онлайн

на главную

Жанры

Вариации на тему STL. Адаптер обобщенного указателя на функцию-член класса

Гусаров Михаил

Шрифт:

R operator(T* p) {

 return (p->*pm);

}

Реализация gen_mem_fun

Теперь реализация gen_mem_fun становится тривиальной:

template<class R, class T>

gen_mem_fun_t<R, T> gen_mem_fun(R (T::*pm)) {

 return gen_mem_fun_t<R, T>(pm);

}

Проблемы

с разными компиляторами

Специализация шаблонных функций – членов шаблонного класса

К сожалению, вышеприведенный код не будет компилироваться на компиляторах, не поддерживающих специализацию шаблонов-функций – членов шаблонов классов.

ПРИМЕЧАНИЕ К таким относятся, например, gcc-2.95 и gcc-2.96

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

template<class R, class T, class TT>

struct gen_mem_fun_operator {

 R operator(TT p, R (T::*pm)) {return (p.operator->->*pm);}

};

template<class R, class T>

struct gen_mem_fun_operator<R, T, T*> {

 R operator(T* p, R (T::*pm)) {return (p->*pm);}

};

Тогда наш gen_mem_fun_t запишется так:

tem
pl
ate<class R, class T>

struct gen_mem_fun_t {

 explicit gen_mem_fun_t(R (T::*pm_)): pm(pm_) {}

 template<class TT> R operator(TT p) {return gen_mem_fun_operator<R, T, TT>(p, pm);}

private:

 R (T::*pm);

};

Проблема “return void”

Посмотрим внимательнее на реализацию функции operator в нашем адаптере. Что будет, если мы захотим в качестве типа возвращаемого значения функции использовать void? Наша функция запишется так: void operator {return void;}. С точки зрения стандарта все хорошо, но все в нашем мире определяется стандартом: есть компиляторы, которые не воспринимают такую конструкцию как допустимую.

ПРИМЕЧАНИЕ Таков, к примеру, Microsoft Visual C++ 6.0/7.0

К счастью, на помощь нам опять приходит частичная специализация:

template<class T, class TT>

struct gen_mem_fun_operator<void, T, TT> {

 void operator(TT p, void (T::*pm)) {(p.operator->->*pm);}

};

template<class T>

struct gen_mem_fun_operator<void, T, T*> {

 void operator(T* p, void (T::*pm)) {(p->*pm);}

};

Частичная

специализация

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

ПРИМЕЧАНИЕ К таким относится и Microsoft Visual C++ 6.0/7.0

Для решения этой проблемы можно использовать паттерн «traits», специфичный для C++. К сожалению, он не сможет помочь в случае, когда один из параметров шаблона специализируется типом, зависящим от другого параметра шаблона, но в случае проблемы «return void» он помочь сможет.

ПРИМЕЧАНИЕ Вопрос, реально ли вообще симулировать частичную специализацию шаблонов, где специализируемый параметр шаблона зависит от неспециализируемого, на компиляторе, не поддерживающем частичную специализацию шаблонов и поддерживающем специализацию вообще только для глобальных классов и функций, остается открытым. Я такой возможности не вижу. Таким образом, создать без помощи препроцессора код нашего адаптера, компилирующийся и под gcc и под Visual C++, не представляется возможным.

Введем вспомогательный класс

template<class R>

struct gen_mem_fun_traits {

 template<class T>

 struct signature {

typedef gen_mem_fun_base_t<R, T> base;

 };

};

template<> struct gen_mem_fun_traits<void> {

 template<class T> struct signature {

typedef void_gen_mem_fun_base_t<T> base;

 };

};

Этот класс специализирован для специального случая функции, возвращающей void. Таким образом, хоть нам и придется ввести дополнительный класс для функций, возвращающих void, для клиента это будет выглядеть единообразно: gen_mem_fun_traits<rettype>::signature<memberclass>::base.

Сами по себе ветви вычислений различных вариантов тривиальны:

template<class R, class T>

struct gen_mem_fun_base_t {

protected:

 gen_mem_fun_base_t(R (T::*pm_)): pm(pm_) {}

public:

 template<class TT> R operator(TT p) {return (p.operator->->*pm);}

 template<> R operator(T* p) {return (p->*pm);}

private:

 R (T::*pm);

};

template<class T>

struct void_gen_mem_fun_base_t {

123
Поделиться:
Популярные книги

Live-rpg. эволюция-3

Кронос Александр
3. Эволюция. Live-RPG
Фантастика:
боевая фантастика
6.59
рейтинг книги
Live-rpg. эволюция-3

Пушкарь. Пенталогия

Корчевский Юрий Григорьевич
Фантастика:
альтернативная история
8.11
рейтинг книги
Пушкарь. Пенталогия

Хроники разрушителя миров. Книга 8

Ермоленков Алексей
8. Хроники разрушителя миров
Фантастика:
фэнтези
5.00
рейтинг книги
Хроники разрушителя миров. Книга 8

Адъютант

Демиров Леонид
2. Мания крафта
Фантастика:
фэнтези
6.43
рейтинг книги
Адъютант

Эфир. Терра 13. #2

Скабер Артемий
2. Совет Видящих
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Эфир. Терра 13. #2

Кодекс Крови. Книга VI

Борзых М.
6. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга VI

Измена

Рей Полина
Любовные романы:
современные любовные романы
5.38
рейтинг книги
Измена

Я – Орк. Том 2

Лисицин Евгений
2. Я — Орк
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я – Орк. Том 2

Законы Рода. Том 2

Flow Ascold
2. Граф Берестьев
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 2

Корпулентные достоинства, или Знатный переполох. Дилогия

Цвик Катерина Александровна
Фантастика:
юмористическая фантастика
7.53
рейтинг книги
Корпулентные достоинства, или Знатный переполох. Дилогия

Тринадцатый

NikL
1. Видящий смерть
Фантастика:
фэнтези
попаданцы
аниме
6.80
рейтинг книги
Тринадцатый

Темный Патриарх Светлого Рода

Лисицин Евгений
1. Темный Патриарх Светлого Рода
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Темный Патриарх Светлого Рода

Раб и солдат

Greko
1. Штык и кинжал
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Раб и солдат

Волк 5: Лихие 90-е

Киров Никита
5. Волков
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Волк 5: Лихие 90-е