为什么我不能在gcc中访问前辈模板化成员函数的祖先方法

Why I cannot access ancestor methods from predecessor templated member functions in gcc?

本文关键字:成员 函数 方法 祖先 不能 gcc 访问 为什么      更新时间:2023-10-16

我有一个类成员函数模板的问题。似乎gcc在没有显式的模板实例化的情况下过早地试图从语义上分析代码。

让代码说话

A.h(基类):

#ifndef __A_H__
#define __A_H__
class A {
public:
    A* ptr;
    template<class T>
    void method() {
        ((B*) ptr)->invoke();
    }
};
#endif 

B.h(祖先):

#ifndef __B_H__
#define __B_H__
#include<cstdio>
class B : public A {
        public:
        void invoke() {
                printf("Method invokedn");
        }
};
#endif 

main.cpp:

#include"A.h"
#include"B.h"
int main() {
        A a;
        a.ptr = new B();
        a.method<int>();
}

此代码在Visual Studio 2010中编译和运行良好,但在gcc 4.5中编译失败,出现以下错误:

In file from main.cpp:1:0: A.h: In member function ' voidA::method() ': A.h:10:5: error: ' B '未在此作用域中声明A.h:10:7:错误:')'标记之前期望的主表达式A.h:10:9: error: expected ') ' before ' ptr '

为什么gcc试图在任何实例化请求之前编译A::method<>()的代码?哪个编译器的行为符合标准?

UPDATE:现在我知道Visual Studio的行为不正确。B不是模板参数依赖的,所以它不会在实例化时查找,而是在解析A.h时查找(相关的gcc文档)

由于模板的处理方式,代码在Visual Studio中不正确地编译(基本上它们在被实例化之前被忽略)。在您的代码中,标识符B不依赖于模板参数(T),因此,它必须在定义模板的上下文中可用。

由于B继承自A,这使得一切变得更加复杂,因为您在代码中有一个循环依赖。我会重新考虑设计,如果您认为需要这样做,我会将两个头文件合并为一个:

// merged.h
struct A {
   A* ptr;
   template<class T>
   void method();
};
struct B : public A {
   void invoke() {
      printf("Method invokedn");
   }
};
template <typename T>
void A::method() {
   ((B*) ptr)->invoke();
}

不过,我的建议是重新考虑这种关系是否有意义,因为method施加了ptr 必须B的限制,这让人想起了一些代码气味。

来自cplusplus.com论坛的ne555给了我一些简洁的解决方案:

新A.h:

#ifndef __A_H__
#define __A_H__
class A {
    public:
    A* ptr;
    template<class T>
    void method();
};
#include"B.h"
template<class T>
void A::method(){
    ((B*)ptr)->invoke();
}
#endif