下面的代码有几个常规函数重载,现在还有一个模板函数,如果没有合适的重载,则可以作为包罗万象的函数。
它几乎按照我想要的方式工作,除了使用派生类(之前以常规重载结束)由函数模板处理。
#include <iostream>
class Base { };
class AnotherBase { };
class Derv : public Base{ };
class Derv2 : public Base { };
class DervDerv : public Derv { };
void f(const Base &b)
{
printf("b(Base)\n");
}
void f(const Derv &b)
{
printf("b(Derv)\n");
}
template<class T> void f(const T& t)
{
printf("b(template)\n");
}
int main() {
f(Base());
f(AnotherBase());
f(Derv());
f(Derv2());
f(DervDerv());
return 0;
}
所以我得到的输出是这样的......
b(Base)
b(template)
b(Derv)
b(template)
b(template)
...当我天真的期望是这样的:
b(Base)
b(template)
b(Derv)
b(Base)
b(Derv)
基类的函数重载真的比函数模板“质量较低”吗?如果是这样,有没有简单的方法可以改变这种情况?
最佳答案
这与“质量”无关。它与转换有关,就像任何其他重载一样。要对 f(Derv2());
的调用进行重载解析,编译器将从函数模板中合成如下声明:
void f(const Derv2& t);
它与其他声明的重载相冲突。选择此重载的原因完全相同,当您编写 f(Derv( ));
。
“包罗万象”的模板就能做到这一点,它会捕获没有确切用户定义重载的所有内容。如果你想防止这种情况发生,你需要使用元编程来约束模板。依赖于 SFINAE 的简单技巧如下所示:
template<class T>
auto f(const T& t) -> std::enable_if_t<!std::is_convertible<T*, Base*>::value>
{
printf("b(template)\n");
}
这会产生 exact output you expected 。显然,您需要提前知道要限制什么。
关于c++ - 函数模板和常规重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53977457/