使用成员函数指针跨类调用方法时的模板匹配问题
解决成员函数指针与函数模板的匹配问题
问题根源
- apply1调用失败原因:调用
b.apply1(&Eggs::f1, s)时,模板参数T会从两个位置推导:- 从成员函数指针
void (Eggs::*)(const Spam&)推导出T = const Spam& - 从第二个参数
s(类型Spam)推导出T = Spam
两个推导结果矛盾,编译器无法确定T的类型,导致模板实例化失败。
- 从成员函数指针
- apply2调用失败原因:第二个参数是
my_type_identity<T>类型,但你传递的是Spam对象,类型不匹配;同时T的推导依然存在冲突——成员函数指针推导出T = const Spam&,但my_type_identity<T>没法匹配Spam,最终推导失败。
解决方案
核心思路是让模板参数T只从成员函数指针推导,把第二个参数的类型设置为非推导上下文,避免推导冲突。用你定义的my_type_identity就能实现这个效果:
修正后的代码
template<class T> struct my_type_identity { using type = T; }; struct Spam {}; struct Eggs { void f0(Spam) {} void f1(const Spam&) {} }; template <class C> struct Bread { C c; // 关键修正:第二个参数用非推导上下文,T仅从成员函数指针推导 template <class F, class T> void apply(void (F::*f)(T), typename my_type_identity<T>::type t) { (c.*f)(t); } }; int main() { Spam s; Bread<Eggs> b; b.apply(&Eggs::f0, s); // 正常运行 b.apply(&Eggs::f1, s); // 正常运行:s会自动转成const Spam& }
关键说明
typename my_type_identity<T>::type属于非推导上下文,编译器不会从第二个参数推导T,只会根据成员函数指针确定T的类型。- 对于
f1,T会被推导为const Spam&,第二个参数的类型就是const Spam&,传递Spam对象s时会自动隐式转换,完全符合函数调用要求。 - 如果用C++20及以上版本,直接用标准库的
std::type_identity替代自定义的my_type_identity就行,效果一样。
内容的提问来源于stack exchange,提问作者Captain'Flam
相关产品推荐
相关产品推荐

