Вариации на тему STL. Адаптер обобщенного указателя на функцию-член класса
Шрифт:
Реализация gen_mem_fun
Теперь реализация gen_mem_fun становится тривиальной:
Проблемы
Специализация шаблонных функций – членов шаблонного класса
К сожалению, вышеприведенный код не будет компилироваться на компиляторах, не поддерживающих специализацию шаблонов-функций – членов шаблонов классов.
ПРИМЕЧАНИЕ К таким относятся, например, gcc-2.95 и gcc-2.96
Попробуем обойтись без них. Специализация в той или иной форме нам в любом случае понадобится, так что воспользуемся тем, что есть – частичной специализацией классов. Введем вспомогательный класс и специализируем его для особого случая обычных указателей.
Тогда наш gen_mem_fun_t запишется так:
Проблема “return void”
Посмотрим внимательнее на реализацию функции operator в нашем адаптере. Что будет, если мы захотим в качестве типа возвращаемого значения функции использовать void? Наша функция запишется так: void operator {return void;}. С точки зрения стандарта все хорошо, но все в нашем мире определяется стандартом: есть компиляторы, которые не воспринимают такую конструкцию как допустимую.
ПРИМЕЧАНИЕ Таков, к примеру, Microsoft Visual C++ 6.0/7.0
К счастью, на помощь нам опять приходит частичная специализация:
Частичная
К сожалению, не все компиляторы поддерживают частичную специализацию шаблонных классов.
ПРИМЕЧАНИЕ К таким относится и Microsoft Visual C++ 6.0/7.0
Для решения этой проблемы можно использовать паттерн «traits», специфичный для C++. К сожалению, он не сможет помочь в случае, когда один из параметров шаблона специализируется типом, зависящим от другого параметра шаблона, но в случае проблемы «return void» он помочь сможет.
ПРИМЕЧАНИЕ Вопрос, реально ли вообще симулировать частичную специализацию шаблонов, где специализируемый параметр шаблона зависит от неспециализируемого, на компиляторе, не поддерживающем частичную специализацию шаблонов и поддерживающем специализацию вообще только для глобальных классов и функций, остается открытым. Я такой возможности не вижу. Таким образом, создать без помощи препроцессора код нашего адаптера, компилирующийся и под gcc и под Visual C++, не представляется возможным.
Введем вспомогательный класс
Этот класс специализирован для специального случая функции, возвращающей void. Таким образом, хоть нам и придется ввести дополнительный класс для функций, возвращающих void, для клиента это будет выглядеть единообразно: gen_mem_fun_traits<rettype>::signature<memberclass>::base.
Сами по себе ветви вычислений различных вариантов тривиальны: