我创建了一些使用函数模板和该函数的重载(不是专门化)的代码。当我使用从该参数中派生的类的对象调用该函数时,它将使用模板,从而导致编译错误。我一直在读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)
时,它可以正常编译。
我通过删除模板函数并为所有使用的类型重载来修复它,但这很麻烦,因为它们都做完全相同的事情。
答案 0 :(得分:1)
我给人的印象是,重载的函数总是比模板优先。
这是正确的,但仅当非模板功能和模板功能同等好时。在这种情况下,将使用非模板功能。
在这种情况下,虽然它们并不都一样好。 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
派生的类型调用它。您可以在此live example中看到它的工作。