为啥我不能从 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 中的前身模板化成员函数访问祖先方法?的主要内容,如果未能解决你的问题,请参考以下文章