2

我有如下代码

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)

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

4

2 回答 2

4

billz 已经给出了答案,但我会尽力做出解释。

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

一元 & 运算符的结果是指向其操作数的指针。操作数应为左值或限定 ID。如果操作数是一个限定id,命名某个类C的一个非静态成员m,类型为T,则结果的类型为“指向类型T的类C成员的指针”,并且是一个指定C::m的纯右值。否则,如果表达式的类型是 T,则结果的类型为“指向 T 的指针”,并且是一个纯右值,它是指定对象 (1.7) 的地址或指向指定函数的指针。[注意:特别是,类型“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 中定义,对于这种特殊情况说明:

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

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

于 2013-01-12T05:21:32.730 回答
1

演员表应该使它起作用:

typedef int (B::*Key)() const;
TT<Key(&B::Key)> t;
t.Get();
于 2013-01-12T04:21:16.353 回答