假设你有
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 ‘&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
答案 0 :(得分:4)
void (B::*f)()=&B::f;
起作用,因为来自
的隐式转换void (A::*f)()
到
void (B::*f)()
已应用。
4.11(2)
类型为“指向cv T类型B的成员的指针”的prvalue,其中B是类类型,可以转换为 类型为“指向cv T类型D的成员的指针”的prvalue,其中D是B的派生类(第10条)。
但是,除了nullptr_t转换之外,标准不允许在模板参数中指向成员函数的任何转换:
14.3.2
对于指向成员函数的类型指针的非类型模板参数,如果template-argument是 输入std :: nullptr_t,应用空成员指针转换(4.11);否则,没有转换 应用。如果template-argument表示一组重载的成员函数,则匹配成员 从集合中选择函数(13.4)。
答案 1 :(得分: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::*)()