编译器如何重载模板函数而不改变参数列表

How compiler overloades template function without argument list change?

本文关键字:函数 改变 列表 参数 何重载 重载 编译器      更新时间:2023-10-16

如下面的代码所示,方法get被模板化了。

struct A
{
    int i;
    char c;
};
class SL
{
    static void* m_a;

public:
    template <class T>
    static T* get()
    {
        return static_cast<T*>(m_a);
    }
};
void* SL::m_a = new A{12, 'C'};
int main()
{
    std::cout << SL::get<A>()->i;
    return 0;
}

我不明白的是,当我写SL::get<B>()时,编译器如何创建两个具有相同名称的方法,在同一名称空间中,具有两种不同的返回类型,两者都没有参数,即没有不同的参数列表?他们是如何让彼此超负荷的?或者理解庙函数生成具有相同的名称并通过重载解析解释它们的调用是错误的?

模板实例实际上是不重载的不同的函数。您可以将模板参数<B>视为函数名的一部分。因此,SL::get<A>SL::get<B>实际上是不同的函数(尽管源于相同的模板)。

引用cppreference:

模板实参推导发生在函数模板名查找之后(可能涉及与实参相关的查找)和重载解析之前。

如你所见,重载解析是一个不同的过程。

这是编译器特有的,你不应该太担心。这是如何实现的一个总体思路:

假设你用两个不同的类型调用模板化方法

SL::get<A>();
SL::get<B>();

编译器为这些调用生成两个新方法:

static A* get_a()
{
  // etc..
}

static B* get_b()
{
  // etc..
}

这可能因编译器而异,但它显示了编译器如何避免名称冲突。对于程序员来说,这是同一个方法被调用两次,对于编译器来说,这只是两个不同的方法被不同的代码调用。

模板很容易像其他东西一样命名混淆。当生成确切的get时,它实际上不再称为get,而是称为get@YUQIE或类似的名称。您可以查看本文中的示例。这是实现定义的,所以不同的编译器会以不同的方式来做。例如,在以下代码

template <class T>
T get()
{
    return T();
}
int main()
{
    get<int>();
    get<char>();
    return 0;
}
get被gcc修改为get<int>_Z3getIiEPT_vget<char>_Z3getIcEPT_v