Разрешение перегрузки функции C++ относительно шаблонного типа и иерархии классов
Возможный дубликат:
Приоритет при выборе перегруженных шаблонных функций в C++
Шаблонная функция дает мне возможность работать с различными типами:
template<typename T> void destroy(T* obj) {
delete obj;
}
Но в какой-то момент я хочу сделать некоторую специализацию в иерархии классов:
class Base { virtual void doSomething(); };
class Derived : public Base {};
void destroy(Base* obj) {
obj->doSomething();
delete obj;
}
Намеченная специализированная функция вызывается, если я передаю точный тип Base*
Однако правила разрешения перегрузки, похоже, предпочитают шаблонную версию вместо выполнения статического приведения вверх, если я прошел Derived*
в void detroy()
,
Конечно, я могу сделать все перегруженные функции для всех возможных производных типов, но это менее обслуживаемо.
Я использую Visual C++ 2008, есть ли способ обойти вышеуказанную проблему?
2 ответа
При прочих равных, разрешение перегрузки предпочитает не шаблонные функции шаблонам функций. Однако в этом случае все вещи не равны. Чтобы соответствовать вашей перегрузки для Base*
необходимо преобразование производного в базовый указатель; преобразование не требуется для соответствия шаблону функции. Таким образом, шаблон функции выбран для Derived*
,
"Простое", хотя, вероятно, подверженное ошибкам, решение будет заключаться в Derived*
к Base*
прежде чем вызывать функцию.
По крайней мере, теоретически вы можете использовать подход SFINAE, как предлагает Бен, но вам придется явно отключить шаблон универсальной функции для любых типов, для которых вы предоставляете специализации, в противном случае вы получите неоднозначности перегрузки. Это даже более неосуществимо и подвержено ошибкам, чем явный метод приведения. (Хотя, кто-то здесь может знать другой способ обойти неопределенность перегрузки; мне, конечно, было бы интересно узнать, был ли он).
Visual C++ 2009 не существует.
Возможно, вы сможете специализировать свою функцию с другим шаблоном и использовать SFINAE только для соответствия подтипам Base. Но я не знаю причин, по которым компилятор предпочел бы вторую версию, обычно специализация должна быть "лучше" в некотором смысле, чтобы быть выбранной.
В качестве альтернативы, вы можете использовать SFINAE и класс вспомогательных черт, чтобы общая версия не соответствовала подклассам Base. Если вам нужен пример этого, спросите.
И, конечно, ваша специализация будет использоваться только там, где она видна. Шаблонные функции всегда встроены, они и специализации должны быть в заголовочных файлах, включаемых вызывающей стороной.