简体   繁体   English

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

[英]Cannot convert overloaded function pointer to member function pointer?

I have code as following 我有以下代码

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)

Why and how to a similar way works? 为什么以及如何以类似的方式起作用? Thanks 谢谢

The answer has already been provided by billz, but I will try to produce an explanation. 答案已经由Billz提供,但是我将尝试给出一个解释。

In C++ when obtaining a pointer to member, the result of the expression is not a pointer to member of the type present in the expression, but rather a pointer-to-member of the type where the member is defined. 在C ++中,当获得指向成员的指针时,表达式的结果不是指向表达式中存在的类型的成员的指针,而是指向定义该成员的类型的成员的指针。 That is, the expression &B::Key yields &A::Key , as the member function Key is defined in A and not in B . 也就是说,表达式&B::Key产生&A::Key ,因为成员函数Key是在A定义的,而不是在B定义的。 This is defined in §5.3.1/3, which is hard to read but comes with an example: 这在第5.3.1 / 3节中定义,虽然很难阅读,但附带一个示例:

The result of the unary & operator is a pointer to its operand. 一元&运算符的结果是指向其操作数的指针。 The operand shall be an lvalue or a qualified-id. 操作数应为左值或限定ID。 If the operand is a qualified-id naming a non-static member m of some class C with type T, the result has type “pointer to member of class C of type T” and is a prvalue designating C::m. 如果操作数是一个合格的ID,它用类型T命名某个类C的非静态成员m,则结果的类型为“指向类型T的类C的成员的指针”,并且是一个表示C :: m的前值。 Otherwise, if the type of the expression is T, the result has type “pointer to T” and is a prvalue that is the address of the designated object (1.7) or a pointer to the designated function. 否则,如果表达式的类型为T,则结果的类型为“指向T的指针”,并且是prvalue,它是指定对象(1.7)的地址或指向指定函数的指针。 [ Note: In particular, the address of an object of type “cv T” is “pointer to cv T”, with the same cv-qualification. [注意:特别是,类型为“ cv T”的对象的地址是“ cv T的指针”,具有相同的cv限定。 — end note ] [ Example: —尾注] [示例:

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

— end example ] —结束示例]

This means that your template instantiation is equivalent to: 这意味着您的模板实例化等效于:

TT<B, &A::Key>

While a pointer-to-member to a member of a base can be converted to a pointer-to-member to the a derived type, for the particular case of a non-type non-template template parameter that conversion is not allowed. 虽然指向基础成员的成员的指针可以转换为派生类型的成员的指针,但对于非类型非模板模板参数的特定情况,不允许进行转换。 The conversions for non-type non-template template parameters are defined in §14.3.2/5, which for this particular case states: 非类型非模板模板参数的转换在§14.3.2/ 5中定义,对于这种特殊情况,该状态指出:

For a non-type template-parameter of type pointer to member function, if the template-argument is of type std::nullptr_t, the null member pointer conversion (4.11) is applied; 对于成员函数类型指针的非类型模板参数,如果模板参数的类型为std :: nullptr_t,则应用空成员指针转换(4.11);否则,将转换为空成员指针。 otherwise, no conversions apply. 否则,将不应用任何转换。

Since the &A::Key cannot be converged to int (B::*)() const , the template instantiation is ill-formed. 由于&A::Key无法收敛为int (B::*)() const ,因此模板实例化格式不正确。 By adding the cast in the template instantiation you are forcing the conversion to happen before instantiating the template, and the instantiation becomes valid as there is no need for conversiones. 通过在模板实例化中添加强制类型转换,您将强制转换在实例化模板之前进行,并且该实例化变得有效,因为无需进行转换。

A cast should make it work: 强制转换应使其起作用:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM