简体   繁体   中英

Why is template argument deduction failing for pointer-to-member-function?

With g++ 5.4, this

struct B {
    void f() {}
}; 

struct D : public B {
    void g() {}
};

template <class T>
void foo(void (T::*)(), void (T::*)())
{}

int main()
{
    foo(&D::f, &D::g);
}

fails due to "deduced conflicting types for parameter 'T' ('B' and 'D')". Why isn't T deduced as D, being an exact match?

The type of &D::f would be void ( B::* )(void)

static_assert(::std::is_same<void ( B::* )(void), decltype(&D::f)>::value, "");
static_assert(::std::is_same<void ( D::* )(void), decltype(&D::f)>::value, ""); // error
static_assert(::std::is_same<void ( D::* )(void), decltype(&D::g)>::value, "");

The rationale behind this is that otherwise you won't be able to assign a value of &D::f to a variable of void ( B::* )(void) type without a cast even though f is a member of B or compare &D::f == &B::f .

As a workaround you can perform a static_cast:

foo(static_cast<void (D::*)(void)>(&D::f), &D::g);

In addition to VTT 's excellent demonstration . The standard text in question, I believe, is at [expr.unary.op]/3 , emphasis mine:

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 or variant 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 .

The qualified id you used is D::f , but it names a member function of B (I can bring up the lookup rules if you want). So the class type C in the above paragraph, is B . The type therefore resolves to void ( B::* )(void) .

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