模板实例化之前,并非总是选择重载功能

时间:2018-12-21 19:00:04

标签: c++ overloading derived-class function-templates

我创建了一些使用函数模板和该函数的重载(不是专门化)的代码。当我使用从该参数中派生的类的对象调用该函数时,它将使用模板,从而导致编译错误。我一直在读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 :(得分:1)

  

我给人的印象是,重载的函数总是比模板优先。

这是正确的,但仅当非模板功能和模板功能同等好时。在这种情况下,将使用非模板功能。

在这种情况下,虽然它们并不都一样好。 t2TheTest,运行重载解析时,它会找到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派生的类型调用它。您可以在此live example中看到它的工作。