无法将重载函数指针转换为成员函数指针?

时间:2013-01-12 03:56:30

标签: c++ templates overloading

我的代码如下

class A
{
public:
    int Key() const;
};

class B : public A
{};

template<class T, int (T::*MemFunction)() const>
class TT
{
public:
    int Get() const               {return (m_t.*MemFunction)();}

private:
    T m_t;
};

TT<B, &B::Key> t; // Wrong, cannot convert overloaded function
                  // to int (T::*MemFunction)() (VS2010)

为什么以及如何以类似的方式运作?感谢

2 个答案:

答案 0 :(得分:4)

billz已经提供了答案,但我会尝试做出解释。

在C ++中获取指向成员的指针时,表达式的结果不是指向表达式中存在的类型成员的指针,而是指定成员所在类型的成员指针。也就是说,表达式&B::Key会产生&A::Key,因为成员函数KeyA中定义,而不在B中定义。这在§5.3.1/ 3中定义,这很难阅读,但附带一个例子:

  

一元&amp;的结果operator是指向其操作数的指针。操作数应为左值或限定ID。如果操作数是一个qualified-id,命名一个类型为T的某个类C的非静态成员m,则结果类型为“指向类型为C的C类成员的指针”,并且是一个指定C :: m的prvalue。否则,如果表达式的类型是T,则结果具有“指向T的指针”,并且是作为指定对象(1.7)的地址的prvalue或指向指定函数的指针。 [注意:特别是,类型为“cv T”的对象的地址是“指向cv T的指针”,具有相同的cv-qualification。 - 尾注] [例子:

struct A { int i; };
struct B : A { };
... &B::i ... // has type int A::*
  

- 结束示例]

这意味着您的模板实例化等同于:

TT<B, &A::Key>

虽然指向基类成员的成员指针可以转换为指向成员的指针到派生类型,但对于非类型非模板模板参数的特定情况,转换不是允许。非类型非模板模板参数的转换在§14.3.2/ 5中定义,针对此特定情况说明:

  

对于指向成员函数的类型指针的非类型模板参数,如果template-argument的类型为std :: nullptr_t,则应用空成员指针转换(4.11);否则,不适用任何转换。

由于&A::Key无法收敛到int (B::*)() const,因此模板实例化不正确。通过在模板实例化中添加强制转换,您在实例化模板之前强制转换,并且实例化变得有效,因为不需要转换。

答案 1 :(得分:1)

演员阵容应该让它发挥作用:

typedef int (B::*Key)() const;
TT<Key(&B::Key)> t;
t.Get();