C++符号范围搜索顺序与模板和非模板类不同?

elm*_*lmo 16 c++ templates scope

#include <iostream>

void foo()
{
    std::cout << "global foo()" << std::endl;
}

struct A {
    void foo()
    {
        std::cout << "A::foo()" << std::endl;
    }
};

struct B : public A {
    void call()
    {
        foo();
    }
};

int main(int argc, char **argv )
{
    B b;
    b.call();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这给出了预期的结果:

A::foo()
Run Code Online (Sandbox Code Playgroud)

但是在更改了两行之后(B类到模板):

#include <iostream>

void foo()
{
    std::cout << "global foo()" << std::endl;
}

struct A {
    void foo()
    {
        std::cout << "A::foo()" << std::endl;
    }
};

template <typename T> // change here
struct B : public T {
    void call()
    {
        foo();
    }
};

int main(int argc, char **argv )
{
    B<A> b; // and here
    b.call();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我得到了意外的结果:

global foo()
Run Code Online (Sandbox Code Playgroud)

并且使用this->不是一个选项,因为我正在尝试创建一个"后备"机制.

And*_*rey 16

你得到的是预期的结果.这在C++标准中称为"两阶段名称查找".

模板内的名称分为两种类型:

从属 - 依赖于模板参数但未在模板中声明的名称.

非依赖 - 不依赖于模板参数的名称,加上模板本身的名称和在其中声明的名称.

当编译器尝试解析代码中的某个名称时,它首先决定名称是否依赖,并且解析过程源于此区别.虽然非依赖名称是"正常"解析的 - 当定义模板时,依赖名称的解析发生在模板实例化的时刻.

foo();B::call您的示例中,in是一个非依赖名称,因此foo()在模板定义时将其解析为全局.

  • @elmo:Microsoft C++没有正确实现两阶段名称查找.请参阅[此问题](http://stackoverflow.com/questions/6273176). (3认同)
  • @elmo:标准的相关部分是C++ 11 14.6.2/3:"在类或类模板的定义中,如果基类依赖于_template-parameter_,则不会检查基类范围在类模板或成员的定义点或在类模板或成员的实例化期间进行非限定名称查找.(C++ 03 14.6.2/3或多或少说同样的事情,如果你出于某种原因对历史标准感兴趣). (3认同)