c++ - 函数模板和常规重载

标签 c++ overload-resolution function-templates

下面的代码有几个常规函数重载,现在还有一个模板函数,如果没有合适的重载,则可以作为包罗万象的函数。

几乎按照我想要的方式工作,除了使用派生类(之前以常规重载结束)由函数模板处理。

#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)

基类的函数重载真的比函数模板“质量较低”吗?如果是这样,有没有简单的方法可以改变这种情况?

https://ideone.com/jD2lgz

最佳答案

这与“质量”无关。它与转换有关,就像任何其他重载一样。要对 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/

相关文章:

C++ Small Straight(如 yahtzee 或 poker)。 5 掷骰子 (1234)/(2345)/(3456)

java - JNA。 char* 不包含结果

c++ - 我们可以在系统 c 的敏感列表中给出输出端口变量吗?

c++ - 使用 clang 的 QT header 中的错误

c++ - 为什么编译器更喜欢 f(const void*) 而不是 f(const std::string &)?

c++ - 混淆在右值和左值上重载成员函数

具有不可更改的通用引用函数模板的 C++ 重载解决方案

c++ - 为什么 GCC 不允许我将模板参数用于另一个模板的参数?

c++ - Clang:模板推导失败 'double' 与 '<double>'

c++ - 类成员函数模板可以是虚拟的吗?