为什么指向成员函数的指针的模板参数推导失败?
Why is template argument deduction failing for pointer-to-member-function?
对于 g++ 5.4,这
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);
}
由于 "deduced conflicting types for parameter ‘T’ (‘B’ and ‘D’)" 而失败。为什么T不推导为D,完全匹配?
&D::f
的类型将是 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, "");
这背后的基本原理是,否则即使 f
是B
的成员或比较 &D::f == &B::f
.
作为解决方法,您可以执行 static_cast:
foo(static_cast<void (D::*)(void)>(&D::f), &D::g);
除了. The standard text in question, I believe, is at [expr.unary.op]/3,强调我的:
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.
你使用的限定id是D::f
,但是它命名了B
的一个成员函数(如果你需要我可以调出查找规则)。所以上一段中的class类型C
,就是B
。因此类型解析为 void ( B::* )(void)
.
对于 g++ 5.4,这
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);
}
由于 "deduced conflicting types for parameter ‘T’ (‘B’ and ‘D’)" 而失败。为什么T不推导为D,完全匹配?
&D::f
的类型将是 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, "");
这背后的基本原理是,否则即使 f
是B
的成员或比较 &D::f == &B::f
.
作为解决方法,您可以执行 static_cast:
foo(static_cast<void (D::*)(void)>(&D::f), &D::g);
除了
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.
你使用的限定id是D::f
,但是它命名了B
的一个成员函数(如果你需要我可以调出查找规则)。所以上一段中的class类型C
,就是B
。因此类型解析为 void ( B::* )(void)
.