Это просто, как работает разрешение перегрузки. Когда поиск завершается, он находит как шаблон, так и функцию. Затем выбираются типы шаблонов и начинается разрешение перегрузки. В случае аргумента типа MyClass
два candiates являются:
void func<MyClass>(MyClass const&);
void func(MyClass const&);
Какие одинаково хорошие матчи для аргументов, но второй будучи не-шаблон является предпочтительным. В случае MyClassDer
:
void func<MyClassDer>(MyClassDer const&);
void func(MyClass const&);
В этом случае первый является лучшим кандидатом, чем второй, а второй требует преобразования производного-к-основания и подобран.
Существуют различные подходы к прямой отправке, чтобы попасть в ваш код. Простейшие просто принуждать тип аргумента, чтобы быть MyClass
и, таким образом, возврат к первоначальному делу:
func(static_cast<MyClass&>(myClassDer));
Хотя простой, это должно быть сделано везде, и если вы забыли только в одном месте, не то будет называться. Остальные решения - это complex, и вам может потребоваться рассмотреть вопрос о том, не лучше ли было бы предоставлять разные имена функций.
Одним из вариантов является использование SFINAE отключить шаблон, если тип является производным от MyClass
:
template <typename T>
typename std::enable_if<!std::is_base_of<MyClass,MyClassDer>::value>::type
func(T const & t) { ... }
В этом случае, после поиска, компилятор выполнит тип вычет, и он будет выводить T
к будет MyClassDer
, тогда он будет оценивать возвращаемый тип функции (SFINAE также может быть применен к другому шаблону или аргументу функции). is_base_of
даст false
, а enable_if
не будет иметь вложенный тип. Объявление функции будет плохо сформировано, и компилятор потеряет его, оставив разрешение с единственным кандидатом, перегрузкой без шаблонов.
Другим вариантом будет предоставление единого интерфейса шаблона и отправка внутри шаблона или перегрузки (другим именем) с использованием отправки тегов. Идея аналогична, вы оцениваете черту внутри шаблона и вызываете функцию с типом, сгенерированным из этой оценки.
template <typename T>
void func_impl(T const&, std::false_type) {...}
void func_impl(MyClass const&, std::true_type) {...}
template <typename T>
void func(T const &x) {
func_impl(x,std::is_base_of<MyClass,MyClassDer>::type());
}
Есть и другие варианты, но это две распространенные из них, а остальные в основном базируются на одних и тех же принципах.
Снова рассмотрим, стоит ли проблема сложности решения. Если вызов func
сам выполняется внутри общего кода, простое изменение имени функции решит проблему без излишней сложности, которую вы или другие поддерживающие могут иметь проблемы с сохранением.
Это, кажется, правильное решение. Я собираюсь посмотреть, как реализовать это с помощью boost. – user2811040
@ user2811040 'boost :: enable_if' и' boost :: is_base_of'. Вот и все. – Angew
@ user2811040 И без C++ 11 переместите второй параметр шаблона в трюк указателя. – Angew