【问题标题】:C++ name lookup affected by declaration of a template method受模板方法声明影响的 C++ 名称查找
【发布时间】:2015-01-29 11:50:38
【问题描述】:

我不明白以下 C++ 代码 sn-p(使用 GCC-4.7 测试)中对 static_cast 的需求:

#include <cstdio>

class Interface
{
public:
    virtual void g(class C* intf) = 0;

    virtual ~Interface() {}
};

class C
{
public:
    void f(int& value)
    {
        printf("%d\n", 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);

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

void f(class Implementation& i);

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

void f(Interface* i);

)。

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

【问题讨论】:

  • 您似乎在问为什么完美匹配优于需要转换为基类指针的不完美匹配。答案很明显——完美匹配更好。

标签: c++ templates overloading name-lookup


【解决方案1】:

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

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

其次,重载集中包含三个函数:C::f(int&amp;)C::f(Interface*)C::f&lt;Implementation*&gt;(Implementation*&amp;)。请注意,template 包含在内,因为它的模板参数可以从调用它的参数中推断出来。

现在编译器开始检查哪个函数适合“最佳”:

  • C::f(int&amp;) 根本不能用这个参数调用。
  • 可以调用C::f(Interface*),但需要进行一次标准转换(指向派生的指针 -> 指向基址的指针)
  • C::f&lt;Implementation*&gt;(Implementation*&amp;) 可以调用 任何转换

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

【讨论】:

    猜你喜欢
    • 2016-08-06
    • 1970-01-01
    • 1970-01-01
    • 2019-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-19
    • 1970-01-01
    相关资源
    最近更新 更多