为什么我不能在gcc中访问前辈模板化成员函数的祖先方法
Why I cannot access ancestor methods from predecessor templated member functions in gcc?
我有一个类成员函数模板的问题。似乎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
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 将公共但非静态的成员函数与ALGLIB集成
- 使用指向成员的指针将成员函数作为参数传递
- 将重载的成员函数传递给函数模板
- 我不小心调用了一个没有自己类对象的成员函数.但这是怎么回事呢
- 如何在C++中使用非静态成员函数作为回调函数
- C++错误C2600:无法定义编译器生成的特殊成员函数(必须首先在类中声明)
- 关联容器的下界复杂性:成员函数与非成员函数
- 在 C++ 中用派生类型重写成员函数
- 链表的泛型函数remove()与成员函数remove)
- 如何将lambda作为模板类的成员函数参数
- constexpr构造函数需要常量成员函数时出现问题
- 将自由函数绑定为类成员函数
- 区分非成员函数和头文件中的成员函数
- 如何从子成员函数修改父公共成员变量
- 保留对其他类的成员函数的引用
- 在运算符重载定义中使用成员函数(const错误)
- 内联如何影响模块接口中的成员函数
- 将成员函数指针作为参数传递给模板方法