You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何利用函数实参推导可调用模板函数的模板参数?

问题分析

直接传递模板函数名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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 22:12:47