Перегруженная функция не всегда выбирается перед созданием шаблона - PullRequest
0 голосов
/ 21 декабря 2018

Я создал некоторый код, который использует шаблон функции и перегрузку (не специализацию) этой функции.Когда я вызываю функцию с объектом класса, который является производным от параметра в ней, он использует шаблон, что приводит к ошибке компиляции.Я читал http://www.gotw.ca/publications/mill17.htm и у меня сложилось впечатление, что перегруженные функции всегда будут иметь преимущество перед шаблонами.Я создал похожий пример бездействия:

class ITest
{
public:
    virtual void foo()=0;
};
class TheTest:public ITest
{
public:
    virtual void foo()
    {
    }
};
class test
{
public:
    template<typename T>
    void handle(T par)
    {
        par++;
    }    
    void handle(ITest &t)
    {
        t.foo();
    }
};
void TestThem()
{
    test t;
    t.handle(2);
    t.handle(3.0);
    TheTest t2;
    t.handle(t2);
}

Я бы ожидал, что t.handle(t2) вызовет перегруженный void handle(ITest &t), поскольку TheTest является производным от ITest.Однако компилятор выбирает шаблон, который генерирует ошибку.Когда я изменяю void handle(ITest &t) на void handle(TheTest &t), он прекрасно компилируется.

Я исправил это, удалив функцию шаблона и перегрузив все используемые типы, но это громоздко, поскольку все они делают одно и то же.

1 Ответ

0 голосов
/ 21 декабря 2018

У меня сложилось впечатление, что перегруженные функции всегда будут иметь преимущество перед шаблонами.

Это верно, но только когда функции без шаблонов и шаблонные функции одинаково хороши.В этом случае используется не шаблонная функция.

В этом случае, хотя они не одинаково хороши.t2 - это TheTest, когда запускается разрешение перегрузки, он находит void handle(ITest &t) и void handle(TheTest par) (я создал экземпляр шаблона здесь).Так как версия шаблона даст точное совпадение, она является лучшей функцией и выбрана.

Способ исправить это - заставить шаблон работать только для типов, которые не являются производными от ITest.Если вы измените функцию шаблона на

template<typename T, std::enable_if_t<!std::is_base_of_v<ITest, T>, bool> = true>
void handle(T par)
{
    par++;
}  

, тогда она будет вызываться только для типов, которые не являются производными от ITest.Вы можете увидеть, как это работает в этом живом примере .

...