为何C++编译器无法推导该Lambda对应的模板参数类型?
Let’s break down exactly why the compiler can’t match your call_with function, even though it seems like T should obviously be int.
The Root Cause: Template Argument Deduction Rules
When the compiler tries to instantiate a template function like call_with, it deduces template arguments independently for each function parameter. Here’s what’s happening in your case:
- For the first parameter (
std::function<void(T)> f), you’re passing a lambda. A lambda has its own unique, compiler-generated type—it’s not astd::function. Template deduction doesn’t consider implicit conversions (like converting a lambda tostd::function) when matching parameter types. So the compiler can’t figure out whatTshould be from this argument alone. - For the second parameter (
T val), you’re passing42, which is anint, so the compiler deducesT = inthere.
The problem is that template deduction requires all deduced instances of T to agree. Since the first parameter couldn’t deduce T (no direct type match), the compiler rejects the candidate template—even though the second parameter gave a valid T. The compiler won’t "backfill" the T from the second parameter to make the first parameter’s type work.
Fixes for Your Code
Here are three straightforward ways to get your code compiling:
1. Explicitly Specify the Template Argument
Tell the compiler exactly what T is, so it doesn’t have to deduce it from the first parameter:
int main() { auto print = [](int x) { std::cout << x; }; call_with<int>(print, 42); // Explicitly set T=int }
Now the compiler knows to convert the lambda to std::function<void(int), which works perfectly.
2. Accept Any Callable Type (Better Flexibility)
Instead of restricting the first parameter to std::function, make the template accept any callable type. This is more efficient (avoids std::function overhead) and eliminates deduction issues:
template <typename F, typename T> void call_with(F f, T val) { f(val); } int main() { auto print = [](int x) { std::cout << x; }; call_with(print, 42); // Now works: F is the lambda's type, T is int }
3. Use std::type_identity to Disable Deduction for the First Parameter (C++20+)
If you really want to keep using std::function, you can mark the T in the first parameter as a non-deduced context using std::type_identity_t. This forces the compiler to only deduce T from the second parameter:
#include <type_traits> // For std::type_identity template <typename T> void call_with(std::function<void(std::type_identity_t<T>)> f, T val) { f(val); } int main() { auto print = [](int x) { std::cout << x; }; call_with(print, 42); // T is deduced as int from the second parameter }
Now the compiler uses T=int from the second argument, and the lambda can implicitly convert to std::function<void(int).
内容的提问来源于stack exchange,提问作者Michał Jaworski

