简体   繁体   中英

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.

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. That is, the expression &B::Key yields &A::Key , as the member function Key is defined in A and not in B . This is defined in §5.3.1/3, which is hard to read but comes with an example:

The result of the unary & operator is a pointer to its operand. The operand shall be an lvalue or a qualified-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. 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. [ Note: In particular, the address of an object of type “cv T” is “pointer to cv T”, with the same cv-qualification. — 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:

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; otherwise, no conversions apply.

Since the &A::Key cannot be converged to int (B::*)() const , the template instantiation is ill-formed. 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();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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