fiz*_*zer 13 c++ templates argument-deduction
用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);
}
Run Code Online (Sandbox Code Playgroud)
由于"推断出参数'T'('B'和'D')的冲突类型而失败".为什么不将T推导为D,完全匹配?
use*_*670 13
类型&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, "");
Run Code Online (Sandbox Code Playgroud)
这背后的基本原理是,否则即使是成员或比较,您也无法在没有强制转换的情况&D::f下为变量赋值.void ( B::* )(void)fB&D::f == &B::f
作为解决方法,您可以执行static_cast:
foo(static_cast<void (D::*)(void)>(&D::f), &D::g);
Run Code Online (Sandbox Code Playgroud)
Sto*_*ica 12
除了VTT的出色演示.我相信,有问题的标准文本是[expr.unary.op]/3,强调我的:
一元&运算符的结果是指向其操作数的指针.操作数应为左值或限定ID.如果操作数是一个qualified-id,命名一个类型为T的某个类C的非静态或变体成员m,则结果类型为"指向类型为C的C类成员的指针",并且是一个指定C ::的prvalue米.
您使用的限定ID是D::f,但它命名成员函数B(如果需要,我可以调出查找规则).所以上面的类类型C是B.因此该类型解析为void ( B::* )(void).