According to the C++23 standard, what is the output of this program?
#include <functional>
#include <iostream>
template <typename T>
void call_with(std::function<void(T)> f, T val)
{
f(val);
}
int main()
{
auto print = [] (int x) { std::cout << x; };
call_with(print, 42);
}What is the type of print, and how will it match the template parameter?
The program has a compilation error
The compiler tries to deduce T for every parameter and checks if the deduced types match. Because a lambda is of completely different type, it cannot be matched against std::function and the deduction process fails. §[temp.deduct.type]¶2:
Type deduction is done independently for each
P/Apair, and the deduced template argument values are then combined. If type deduction cannot be done for anyP/Apair, (...) template argument deduction fails.
This problem can be fixed by turning the first parameter into a so-called nondeduced context.
§[temp.deduct.type]¶5 in the standard:
The non-deduced contexts are:
— The nested-name-specifier of a type that was specified using a qualified-id.
— (...)
And also §[temp.deduct.type]¶6:
When a type name is specified in a way that includes a non-deduced context, all of the types that comprise that type name are also non-deduced. However, a compound type can include both deduced and non-deduced types.
[Example 2: If a type is specified as
A, both::B TandT2are non-deduced. Likewise, if a type is specified asA::X,I,J, andTare non-deduced. If a type is specified asvoid f(typename A, the::B, A ) TinAis non-deduced but the::B TinAis deduced. — end example]
In particular, a helper struct template that typedefs the template parameter can be used:
template <typename T>
struct type_identity
{
typedef T type;
};
This helper struct can then turn std::function into a nondeduced context:
template <typename T>
void call_with(typename type_identity<std::function<void(T)>>::type f, T val)
{
f(val);
}
std::type_identity is available in the standard library since C++20.
The problem can also be solved in a less general way (at each call site) by explicitly specifying the template argument:
call_with<int>(print, 42);