带Lambda参数的成员函数指针模板适配方案问询
适配带Lambda参数的成员函数作为模板参数的解决方案
先回顾原有成员函数指针作为模板参数的基础用法:
struct Foo { void Bar() { // do something } }; template <typename TOwner, void(TOwner::*func)()> void Call(TOwner *p) { (p->*func)(); } int main() { Foo a; Call<Foo, &Foo::Bar>(&a); return 0; }
但当成员函数Foo::Bar接受满足has_call_operator概念的Lambda作为参数时,原有模板写法无法直接适配——核心原因是Foo::Bar本质是模板成员函数(使用了auto形参占位符加概念约束),而非普通成员函数。
问题代码分析
用户给出的待修改代码:
template<typename T> concept has_call_operator = requires { &T::operator(); }; struct Foo { // 这是缩写函数模板,每个不同Lambda类型会生成独立的Bar实例 void Bar(has_call_operator auto lambda) {} }; template <typename TOwner, void(TOwner::*func)(???)> void CallFoo(TOwner *p) { (p->*func)([](){}); }
这里的???无法填入固定类型,因为Bar的参数类型是模板参数,每个Lambda的类型都是唯一的。需要调整CallFoo的模板参数设计来解决问题。
解决方案
方案一:使用C++20 auto非类型模板参数(推荐)
利用C++20支持的auto非类型模板参数,让编译器自动推导成员函数指针的完整类型,无需手动指定参数类型:
template<typename T> concept has_call_operator = requires { &T::operator(); }; struct Foo { void Bar(has_call_operator auto lambda) {} }; // 用auto推导成员函数指针的完整类型 template <typename TOwner, auto func> void CallFoo(TOwner *p) { (p->*func)([](){}); } int main() { Foo a; // 明确指定Bar的模板实例(传入Lambda类型作为模板参数) auto lambda = [](){}; CallFoo<Foo, &Foo::Bar<decltype(lambda)>>(&a); return 0; }
方案二:显式添加Lambda类型作为模板参数
如果需要保留原有模板参数结构,可以将Lambda类型也作为模板参数传入,并通过静态断言确保其满足概念约束:
template<typename T> concept has_call_operator = requires { &T::operator(); }; struct Foo { void Bar(has_call_operator auto lambda) {} }; // 新增Lambda类型模板参数,约束其满足has_call_operator template <typename TOwner, typename Lambda, void(TOwner::*func)(Lambda)> void CallFoo(TOwner *p) { static_assert(has_call_operator<Lambda>, "传入的类型必须拥有调用运算符"); (p->*func)([](){}); } int main() { Foo a; using LambdaType = decltype([](){}); // 传入所有者类型、Lambda类型、对应的Bar实例指针 CallFoo<Foo, LambdaType, &Foo::Bar<LambdaType>>(&a); return 0; }
关键说明
Foo::Bar(has_call_operator auto lambda)是C++20引入的缩写函数模板,本质是模板成员函数,每个不同的Lambda类型都会生成一个独立的Bar实例。- 模板成员函数的指针无法直接作为非类型模板参数使用,必须先明确实例化(指定Lambda类型),或通过
auto让编译器推导完整的成员函数指针类型。
内容的提问来源于stack exchange,提问作者PyOPTProblem
相关产品推荐
相关产品推荐

