如何利用函数实参推导可调用模板函数的模板参数?
问题分析
直接传递模板函数名baz给bar时,baz是一个函数模板族而非具体的可调用对象。编译器无法同时完成T的推导和Func的匹配——因为std::invocable<T&, const Foo&>约束需要先确定T,才能确定baz应该实例化为哪个版本。
解决方案
方案1:限定第二个参数为匹配签名的函数指针
修改bar的参数类型,直接指定第二个参数为对应签名的函数指针。当T从第一个参数推导完成后,编译器会自动实例化匹配的baz<T>:
#include <concepts> struct Foo {}; template<typename T> void baz(T& t, const Foo&) {} template<typename T> void bar(T& obj, void(*f)(T&, const Foo&)) { Foo foo{}; f(obj, foo); } int main() { int a{0}; bar(a, baz); // 自动推导T=int,实例化baz<int> }
这种方法最贴合需求,无需显式指定模板参数,代码改动最小。
方案2:用lambda包裹转发
如果需要保留std::invocable的灵活性(支持 functor、lambda 等多种可调用对象),可以用lambda包裹baz,让编译器通过lambda的调用操作符自动推导:
#include <concepts> struct Foo {}; template<typename T> void baz(T& t, const Foo&) {} template<typename T, std::invocable<T&, const Foo&> Func> void bar(T& obj, Func f) { Foo foo{}; f(obj, foo); } int main() { int a{0}; bar(a, [](auto& t, const Foo& foo) { baz(t, foo); }); }
方案3:将baz改为函数对象
把baz从函数模板改为带模板调用操作符的结构体,使其成为一个可直接传递的可调用对象,编译器会通过std::invocable约束自动推导模板参数:
#include <concepts> struct Foo {}; struct Baz { template<typename T> void operator()(T& t, const Foo&) {} }; template<typename T, std::invocable<T&, const Foo&> Func> void bar(T& obj, Func f) { Foo foo{}; f(obj, foo); } int main() { int a{0}; bar(a, Baz{}); // 自动推导operator()的T=int }
内容的提问来源于stack exchange,提问作者user3001150
相关产品推荐
相关产品推荐

