У меня есть два класса:
class Base {};
class Derived : public Base {};
И две перегруженные функции:
void call(std::unique_ptr<Base> op)
{
std::cout << "First overloading" << std::endl;
}
template<class F>
void call(F f)
{
std::cout << "Second overloading" << std::endl;
}
Давайте назовем это с unique_ptr Derived
call(std::make_unique<Derived>());
Я ожидаю вызова первой функции, однако вместо этого вызывается вторая. Почему компилятор выбирает общую функцию вместо конкретной? Разрешение перегрузки не поддерживает наследование и полиморфизм? Если да, то как я могу это исправить и вызвать первую функцию?
Обе ваши перегрузки являются допустимыми кандидатами. Если вы удалите любой из них, оставшийся по-прежнему будет допустимой перегрузкой. В таком случае, вообще говоря, будет выбрана перегрузка, которая наиболее точно соответствует предоставленным аргументам.
Вы предоставили std::unique_ptr<Derived>
. В первом случае он ожидает std::unique_ptr<Base>
. Существует неявное преобразование из std::unique_ptr<Derived>
в std::unique_ptr<Base>
, поэтому эта перегрузка допустима, но требует преобразования.
Во втором случае F
просто выводится как std::unique_ptr<Derived>
. Он не требует преобразования и более точно соответствует предоставленному аргументу. Поэтому он предпочтительнее.
Редактировать: кажется, я пропустил часть об исправлении.
Вместо этого вы можете сделать перегрузку, которая принимает unique_ptr
шаблон функции. Таким образом, вы можете получить точное совпадение с первой перегрузкой, устраняя необходимость в преобразовании. Вы можете использовать std::enable_if
, чтобы отключить эту перегрузку для unique_ptr
несовместимых типов:
#include <memory>
#include <type_traits>
class Base {};
class Derived : public Base {};
template<class T>
std::enable_if_t<std::is_base_of<Base, T>::value>>
call(std::unique_ptr<T>);
template<class T>
void call(T);
Проблема в том, что вторая перегрузка является точным совпадением, когда T
выводится как std::unique_ptr<Derived>
; в то время как первая перегрузка требует неявного преобразования из std::unique_ptr<Derived>
в std::unique_ptr<Base>
. Тогда 2-й выигрывает в разрешении перегрузки.
Вы можете добавить применить СФИНАЭ:
template<class F>
std::enable_if_t<!std::is_convertible_v<F, std::unique_ptr<Base>>> call(F f)
{
std::cout << "Second overloading" << std::endl;
}
Потому что
F
, выведенный как точное соответствиеunique_ptr<Derived>
, лучше подходит, чем совершенно несвязанный типunique_ptr<Base>
. В любом случае, какова цель общего вызова?