代码之家  ›  专栏  ›  技术社区  ›  Shirik

模板类成员函数不是在实例化时编译的吗?

  •  5
  • Shirik  · 技术社区  · 16 年前

    在将代码从visualstudio移植到gcc时,我发现了一个奇怪的问题。以下代码在visualstudio中编译良好,但在gcc中会导致错误。

    namespace Baz
    {
       template <class T>
       class Foo
       {
       public:
          void Bar()
          {
             Baz::Print();
          }
       }; 
    
       void Print() { std::cout << "Hello, world!" << std::endl; }
    }
    
    int main()
    {
       Baz::Foo<int> foo;
       foo.Bar();
    
       return 0;
    }
    

    t、 cpp:在成员函数“void Baz::Foo::Bar()”中:

    2 回复  |  直到 16 年前
        1
  •  4
  •   jpalecek    16 年前

    gcc是对的。是因为 Baz Baz::Print 从里面看不到 Foo (因为它在它下面)。

    在实例化模板时,只考虑模板定义中可见的名称,而不考虑Koenig查找(在您的情况下,它不会改变任何内容)。

    如果 巴兹 如果是一个结构或类,你的代码就可以工作了,因为它们是分两个阶段(首先声明,然后是主体)进行解析的,所以在结构或类中声明的任何东西都可以在内部看到,例如成员函数,源文件中它们的顺序。

    Baz::打印 .

    14.6.3非从属名称

    模板定义中使用的非依赖名称是使用常规名称查找找到的,并在 它们的使用点。

    14.6.4从属名称解析

    在解析从属名称时,将考虑以下来源的名称:

    • 在模板定义点可见的声明。
    • 来自与函数参数类型相关联的名称空间的声明 从实例化上下文(14.6.4.1)和定义上下文。

    (结束报价)

    Print 是非依赖的(就像现在一样),因为它是在声明之前(在模板定义上下文中)查找的,所以找不到它。如果它是依赖的,就不会是第一种情况(与非依赖时相同),并且 与int(模板参数)没有任何关联,因此也不会根据第二种情况进行搜索。

        2
  •  9
  •   Anthony Williams    16 年前

    gcc是对的。模板的编译分为两个阶段:一个是解析模板,另一个是实例化模板。

    在解析时,任何不依赖于模板参数的内容都会被检查,因此在本例中 Baz::Print 查找时,发现未声明,因此这是一个错误。

    如果电话是 T().Print() 或者其他一些取决于类型的东西 T 然后查找将延迟到实例化时间(或者至少部分延迟——见下文)

    T::Print ),尽管重载解析延迟到实例化时间。这意味着您不能在声明模板之后为限定名添加重载集。

    不合格名称,如just Print 如果任何函数参数依赖于模板参数,则在实例化时查找。所以呢 Print(T()) 将在实例化时查找 Baz::Print(T()) 不是。值得注意的是,实例化时间查找仅限于在声明点可见的名称和通过ADL找到的名称,因此 Foo<int> ,即使是平原 打印(T()) 应该找不到 Baz::打印 如果它是在模板之后声明的(如示例中所示)。

    Foo<T>::Bar 在定义 打印 打印 Foo .