将超类函数作为非类型名模板参数传递

时间:2012-06-21 12:06:29

标签: c++ templates

假设你有

  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

2 个答案:

答案 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::*)()