不能将重载函数指针转换为成员函数指针

Cannot convert overloaded function pointer to member function pointer?

本文关键字:指针 函数 成员 转换 不能 重载      更新时间:2023-10-16

我的代码如下

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)

相似的方式为什么和如何工作?由于

billz已经给出了答案,但我会尽量给出一个解释。

在c++中,当获取指向成员的指针时,表达式的结果不是指向该表达式中存在的类型的成员的指针,而是指向成员所在类型的成员的指针。即表达式&B::Key得到&A::Key,因为成员函数KeyA中定义,而不在B中定义。这是在§5.3.1/3中定义的,它很难阅读,但附带了一个例子:

一元&Operator是指向其操作数的指针。操作数应为左值或限定id。如果操作数是一个限定id,命名某个类型为T的类C的非静态成员m,则结果的类型为"指向类型为T的类C成员的指针",并且是一个指定C::m的右值。否则,如果表达式的类型为T,则结果具有"指向T的指针"类型,并且是一个右值,该右值是指定对象的地址(1.7)或指向指定函数的指针。[注:特别地,类型为"cv T"的对象的地址是"指向cv T的指针",具有相同的cv-限定符。- end note][示例:

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

- end示例]

这意味着你的模板实例化相当于:

TT<B, &A::Key>

虽然指向基类成员的成员指针可以转换为指向派生类型的成员指针,但对于非类型非模板模板形参的特殊情况,不允许转换。非类型非模板模板形参的转换在§14.3.2/5中定义,对于这种特殊情况,它规定:

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

由于&A::Key不能收敛到int (B::*)() const,模板实例化是病态的。通过在模板实例化中添加强制转换,您可以强制转换在模板实例化之前发生,并且实例化变得有效,因为不需要转换。

转换应该使它工作:

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