8

假设你有

  struct A{
  void f(){}
};


struct B:public A{
};


template<typename C,void (C::*f)()>
struct Call{

  void operator()(C* c){
    (c->*f)();
  }
};

为什么

int main(){
  void (B::*f)()=&B::f;    
}

工作但

 Call<B,&B::f> a;

没有,抱怨

could not convert template argument ‘&amp;A::f’ to ‘void (B::*)()

?

Call<A,&A::f>显然有效)

以类似的方式

const void (B::*f)()=&B::f;

cannot convert ‘void (A::*)()’ to ‘const void (B::*)()’ in initialization
4

2 回答 2

4
void (B::*f)()=&B::f;   

有效,因为从隐式转换

void (A::*f)() 

void (B::*f)()

被申请;被应用。

4.11 (2)

“指向类型为 cv T 的 B 的成员的指针”类型的纯右值,其中 B 是类类型,可以转换为类型为“指向类型为 cv T 的 D 的成员的指针”类型的纯右值,其中 D 是派生类 ( B.第 10) 条。

但是,该标准不允许对模板参数中的成员函数的指针进行任何转换,但 nullptr_t 转换除外:

14.3.2

For a non-type template-parameter of type pointer to member function, if the template-argument is of type std::nullptr_t, the null member pointer conversion (4.11) is applied; otherwise, no conversions apply. If the template-argument represents a set of overloaded member functions, the matching member function is selected from the set (13.4).

于 2012-06-21T14:03:08.783 回答
0

该错误准确地说明了问题所在,void (A::*)()并且void (B::*)()是不同的类型。

虽然在这种情况下看起来应该很容易做到,但一般情况会变得复杂得多。考虑一下如果A有几个虚函数并且B有多重继承会发生什么。指向成员函数的指针是非常复杂的野兽,因为它们必须考虑这类事情。看看http://blogs.msdn.com/b/oldnewthing/archive/2004/02/09/70002.aspx

您可以更改B为:

struct B:public A{
    void f() { A::f(); }
};

所以这B::f()确实存在。现在B::f()是一个别名,A::f()它显然是类型void (A::*)()而不是void (B::*)()

于 2012-06-21T13:12:02.083 回答