我正在使用定义接口(interface)的库:
template<class desttype>
void connect(desttype* pclass, void (desttype::*pmemfun)());
我有一个小层次结构
class base {
void foo();
};
class derived: public base { ... };
在derived
的一个成员函数中,我想调用
connect(this, &derived::foo);
但是看起来&derived::foo
其实是base
的一个成员函数指针; gcc 吐出
error: no matching function for call to ‘connect(derived* const&, void (base::* const&)())’
我可以通过显式地将 this
转换为 base *
来解决这个问题;但为什么编译器不能将调用与 desttype = base
匹配(因为 derived *
可以隐式转换为 base *
)?
另外,为什么是&derived::foo
不是derived
的成员函数指针?
最佳答案
首先,当你执行 &class::member
时,结果的类型总是基于成员实际声明的类。这就是一元 &
的工作方式C++。
其次,代码无法编译,因为模板参数推导失败。它从第一个参数导出 desttype = derived
,而从第二个参数导出 desttype = base
。这就是编译失败的原因。 C++ 中的模板参数推导规则没有考虑this
可以转换为base *
类型这一事实。此外,可以争辩说,不是将 this
转换为 base *
类型,正确的方法是将 &derived::foo
从指针转换为 - to-base-member 指向派生成员类型的指针。这两种方法同样可行(见下文)。
第三,C++ 中的成员指针遵循反变 规则,这意味着指向基类成员的指针可以隐式转换为指向派生类成员的指针。在您的情况下,您需要做的就是通过显式指定参数来帮助编译器完成模板参数推导,并且代码应该编译
connect<derived>(this, &derived::foo);
由于 &derived::foo
指针的反方差,上面应该编译,即使它是指向 base
成员的指针。或者你可以做
connect<base>(this, &derived::foo);
由于 this
指针的协方差,这也应该编译。
您还可以对实际参数使用显式转换(正如您在问题中提到的那样)来解决演绎歧义,但我认为在这种情况下,显式指定的模板参数看起来更好。
关于c++ - 层次结构中的成员函数指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2602254/