【发布时间】:2011-04-21 01:05:45
【问题描述】:
我对成员指针有疑问。以下代码无法同时使用 Oracle Solaris Studio 12.2 的 CC 和 cygwin GCC 4.3.4 进行编译,但适用于 Microsoft Visual C++ 2010:
struct A {
int x;
};
struct B : public A {
};
template<typename T> class Bar {
public:
template<typename M> void foo(M T::*p);
};
int main(int, char *[]) {
Bar<B> bbar;
bbar.foo(&B::x);
return 0;
}
在最后一行的下一行,上面提到的两个编译器都找不到Bar<B>::foo(int A::*) 的匹配项。我写了一个简单的测试来确认表达式&B::x的类型实际上是int A::*:
// ...
static void foo(int A::*p) {
std::cout << "A" << std::endl;
}
static void foo(int B::*p) {
std::cout << "B" << std::endl;
}
int main(int, char *[]) {
foo(&B::x); // prints "A", even on MS VC++ 2010
return 0;
}
以下解决方法适用于 GCC(尚未使用 Oracle CC 测试),但由于不明确而在 VC++ 中失败:
template<typename T> class Bar {
public:
template<typename M> void foo(M T::*p);
template<typename M, typename _T_base> inline void foo(M _T_base::*p) {
foo(static_cast<M T::*>(p));
}
};
我的问题:
哪种行为是正确的?显然 VC++ 从int A::* 隐式向上转换到int B::* 以满足对成员函数模板的调用,其他两个编译器不应该考虑这样做吗?
【问题讨论】:
-
对答案也很感兴趣,因为我自己也遇到过类似的问题。我的理解是,由于多重继承,
&B::x被静默转换为&A::x的期望是错误的:B的实例可能包含A的多个实例,因此&B::x(可能)是模棱两可的。跨度> -
从我删除的答案中:
static_cast< int B::* >( &B::x )也有效。 -
@Dummy00001:我怀疑在存在多重继承的情况下,编译器的行为会像所有其他基类成员解析一样,并输出一个错误,说明名称不明确。如果编译器能够解析名称(它应该在这里),那么它应该毫不费力地解析它。
-
@Andre:问题是没有实体
B::x。如果我们将其分解,则有限定符B::,它将我们带入B 的范围,然后是x,它查找开始 与B 的范围的对象。我们找到了一个对象x,如果我们找到两个x,确实会出错,但是x仍然关联A而不是B,因为它所在的范围是A的。
标签: c++ member-pointers