为啥我不能从 gcc 中的前身模板化成员函数访问祖先方法?

Posted

技术标签:

【中文标题】为啥我不能从 gcc 中的前身模板化成员函数访问祖先方法?【英文标题】:Why I cannot access ancestor methods from predecessor templated member functions in gcc?为什么我不能从 gcc 中的前身模板化成员函数访问祖先方法? 【发布时间】:2011-07-14 17:51:09 【问题描述】:

我对类成员函数模板有疑问。似乎 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 invoked\n");
        
;
#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 上编译失败并出现以下错误:

在 main.cpp:1:0 中包含的文件中:A.h:在成员函数‘void A::method()': A.h:10:5: 错误:'B' 未在此范围内声明 A.h:10:7:错误:')' 标记之前的预期主表达式 A.h:10:9:错误:在“ptr”之前需要“)”

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

更新: 现在我知道 Visual Studio 的行为不正确。 B 不依赖于模板参数,因此它不是在实例化时查找的,而是在解析 A.h 期间查找的。 (relevant gcc doc)

【问题讨论】:

【参考方案1】:

由于模板的处理方式,代码不正确在 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 invoked\n");
   
;

template <typename T>
void A::method() 
   ((B*) ptr)->invoke();

不过,我的建议是重新考虑这种关系是否有意义,因为method 施加了ptr 必须B 的限制,这敲响了一些警钟代码味道。

【讨论】:

在实际代码中,它比这要复杂一些。 A 持有 A* 的向量,该向量可能是 B 类型或其他祖先类型。但如果这个指针实际上是 B*(通过虚拟方法 String type() 检查),则必须做一些额外的工作。 @MiKom:使用dynamic_cast检查对象的类型,不要滚动你自己的类型方法。 @DeadMG:是的,我知道。不幸的是,这不是我的决定。【参考方案2】:

来自 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

【讨论】:

以上是关于为啥我不能从 gcc 中的前身模板化成员函数访问祖先方法?的主要内容,如果未能解决你的问题,请参考以下文章

调用模板化成员函数:帮助我理解另一个 *** 帖子中的代码片段

如何从模板类型中获取指向模板化成员函数的指针?

std::async 与共享指针模板化成员函数

使用模板化成员函数显式实例化模板类

在 gcc 上将成员函数指针传递给模板成员函数时出现问题

模板化类的模板化成员方法可以在类定义之外定义吗