函数模板和常规重载
Function template and regular overloads
下面的代码有几个常规函数重载,现在还有一个模板函数,如果没有合适的重载,它可以作为万能的。
它 almost 可以按我想要的方式工作,除了使用派生的 classes(之前以常规重载结束)由函数模板处理。
#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)
基类 class 的函数重载真的比函数模板排名 "lower quality" 吗?如果是这样,有没有简单的方法来改变它?
这与 "quality" 无关。它是关于转换的,就像任何其他重载一样。要对 f(Derv2());
的调用进行重载解析,编译器将从您的函数模板中合成如下声明:
void f(const Derv2& t);
它与其他声明的重载相对立。出于完全相同的原因选择此重载 f(const Derv &)
是比 f(const Base &)
更好的匹配,当您编写 f(Derv());
.
"catch-all" 模板就可以做到这一点,它会捕获所有没有确切的用户定义重载的内容。如果你想防止这种情况,你需要用元编程来约束模板。一个依赖 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。虽然很明显,您需要提前知道要限制什么。
下面的代码有几个常规函数重载,现在还有一个模板函数,如果没有合适的重载,它可以作为万能的。
它 almost 可以按我想要的方式工作,除了使用派生的 classes(之前以常规重载结束)由函数模板处理。
#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)
基类 class 的函数重载真的比函数模板排名 "lower quality" 吗?如果是这样,有没有简单的方法来改变它?
这与 "quality" 无关。它是关于转换的,就像任何其他重载一样。要对 f(Derv2());
的调用进行重载解析,编译器将从您的函数模板中合成如下声明:
void f(const Derv2& t);
它与其他声明的重载相对立。出于完全相同的原因选择此重载 f(const Derv &)
是比 f(const Base &)
更好的匹配,当您编写 f(Derv());
.
"catch-all" 模板就可以做到这一点,它会捕获所有没有确切的用户定义重载的内容。如果你想防止这种情况,你需要用元编程来约束模板。一个依赖 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。虽然很明显,您需要提前知道要限制什么。