C++受模板方法声明影响的名称查找

C++ name lookup affected by declaration of a template method

本文关键字:查找 影响 模板方法 声明 C++      更新时间:2023-10-16

我不明白以下C++代码片段中需要static_cast(使用 GCC-4.7 测试):

#include <cstdio>
class Interface
{
public:
    virtual void g(class C* intf) = 0;
    virtual ~Interface() {}
};
class C
{
public:
    void f(int& value)
    {
        printf("%dn", value);
    }
    void f(Interface* i)
    {
        i->g(this);
    }
    template <typename T>
    void f(T& t);
    //void f(class Implementation& i);
};
class Implementation : public Interface
{
public:
    Implementation(int value_) : value(value_) {}
    void g(C* intf)
    {
        intf->f(value);
    }
private:
    int value;
};
int main()
{
    C a;
    Implementation* b = new Implementation(1);
    //a.f(b); // This won't work: undefined reference to `void C::f<Implementation*>(Implementation*&)'
    a.f(static_cast<Interface*>(b));
    delete b;
    return 0;
}

如果我省略static_cast,我会收到链接器错误,因为它想要使用:

template <typename T>
void f(T& t);

而不是:

void f(Interface* i);

另一方面,如果我将模板化方法替换为以下内容(在上面的代码片段中注释掉):

void f(class Implementation& i);

然后我没有收到错误,我可以看到在运行时调用了"正确"方法(即:

void f(Interface* i);

)。

为什么模板方法的声明会影响名称查找?提前非常感谢,

当对a.f(b)执行重载解析时,编译器会注意到两个事实:

首先,您尝试使用类型 Implementation* 的左值调用f

其次,重载集中有三个功能:C::f(int&)C::f(Interface*)C::f<Implementation*>(Implementation*&)。请注意,包含template,因为它的模板参数可以从调用它的参数中推断出来。

现在编译器开始检查哪个函数适合"最好":

  • C::f(int&)根本不能用这个论点来称呼。
  • 可以调用C::f(Interface*),但需要一个标准转换(指向派生的指针 ->指向基的指针)
  • 无需任何转换即可调用C::f<Implementation*>(Implementation*&)

因此,模板非常简单地最适合。但是,由于您没有为模板定义实现,因此链接器稍后会出现错误消息,指出它找不到您尝试调用的函数。