我有一个关于成员指针的问题。以下代码无法使用 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::* 为了满足对成员函数模板的调用,其他两个编译器不应该考虑这样做吗?

有帮助吗?

解决方案

转换自 int A::*int B::* 是允许的,这不是问题。问题出在模板参数推导中,如果您尝试以下提供模板参数的程序,您会看到 <int> 为了 B::foo 并编译,以及一个非成员函数 foo2 这会产生与以下相同的错误 B::foo 以前做过。

struct A {
  int x;
};

struct B : public A {
};

template <typename T> class Bar {
public:
  template<typename M> void foo(M T::*p);
};

template<typename M> void foo2(M B::*p);

int main(int, char*[]) {
  Bar<B> bbar;
  bbar.foo<int>(&B::x);
  foo2(&B::x); // error, but foo2<int>(&B::x) would work.
  return 0;
}

我认为编译器应该推断模板参数的情况不包括这种情况 <int> 在其自己的。14.8.2.1p3:

一般来说,推导过程尝试找到使推导的 A 与 A 相同的模板参数值(在类型 A 如上所述进行转换之后)。但是,在三种情况下允许存在差异:

  • 如果原始 P 是引用类型,则推导的 A(即引用引用的类型)可以比 A 更具 cv 限定性。
  • A 可以是另一个指针或指向成员类型的指针,可以通过限定转换 (conv.qual) 转换为推导的 A。
  • 如果 P 是一个类,并且 P 具有 template-id 形式,则 A 可以是推导的 A 的派生类。同样,如果 P 是指向 template-id 形式的类的指针,则 A 可以是指向由推导的 A 所指向的派生类的指针。

这里“P”是模板函数的参数类型: M B::*p, ,其中模板类型参数 M 待确定。“A”是实际参数的类型: int A::*. 。P 和 A 当然不是引用或类,并且我们为此工作所需的指针到成员转换的类型不是限定转换(它仅描述 const/易失性操作,例如 X*const X* 或者 int X::*const int X::*).

因此无法推导模板参数,您应该添加 <int> 将显式模板参数添加到您的代码中。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top