Разрешение перегрузки в случае шаблонов и наследования в unique_ptr - PullRequest
5 голосов
/ 30 мая 2019

У меня есть два класса:

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>());

Я ожидаю вызова первой функции, однако вместо нее вызывается вторая. Почему компилятор выбирает обобщенную функцию вместо конкретной? Разрешение перегрузки не поддерживает наследование и полиморфизм? Если так, как я могу это исправить и вызвать первую функцию?

Ответы [ 2 ]

6 голосов
/ 30 мая 2019

Обе ваши перегрузки являются действительными кандидатами. Если вы удалите любой из них, оставшийся будет по-прежнему допустимой перегрузкой. В таком случае, в широком смысле, будет выбрана перегрузка, которая будет наиболее точно соответствовать предоставленным аргументам.

Вы предоставили 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 s несовместимых типов:

#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);
2 голосов
/ 30 мая 2019

Проблема в том, что вторая перегрузка является точным соответствием, когда T выводится как std::unique_ptr<Derived>;в то время как 1-я перегрузка требует неявного преобразования из std::unique_ptr<Derived> в std::unique_ptr<Base>.Затем 2-й выигрывает в разрешении перегрузки.

Вы можете добавить команду SFINAE :

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;
}

LIVE

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...