I know that a lambda
object is not a std::function
object, so I understand that this would not work:
template <typename ...args_t>
void func(std::function<void(args_t...)> function_, args_t ...args){
/// do something here
}
void test() {
func([](int a){ }, 1);
}
but why would it work if I add a type_identity to wrap it?
template <typename T>
struct type_identity {
using type = T;
};
template <typename T>
using type_identity_t = typename type_identity<T>::type;
template <typename... args_t>
void func_wrapped(type_identity_t<std::function<void(args_t...)>> function_,
args_t ...args) {
static_assert(std::is_same< std::function<void(args_t...)>,
type_identity_t<std::function<void(args_t...)>>
>::value,
"different type");
/// do something here
}
void test() {
func_wrapped([](int a){ }, 1);
}
as far as I can see, these two look pretty much the same, and it even passed the static_assert
which means they are the same to std::is_same
.
but the compiler just doesn't think so. it told me that the in former code, lambda cannot match any function, while the latter one can.
error: no matching function for call to ‘func(test()::<lambda(int)>, int)’
so, my question is: why do they behave differently? what did type_identity do implicitly?
The former code doesn't work because implicit conversion (from lambda to std::function
) won't be considered in template argument deduction, which causes deduction of template parameter args_t
on the 1st function parameter function_
failing.
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
The latter code works because of non-deduced context:
In the following cases, the types, templates, and non-type values that are used to compose P do not participate in template argument deduction, but instead use the template arguments that were either deduced elsewhere or explicitly specified.
- The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id:
With the usage of type_identity
the 1st function parameter function_
is excluded from template argument deduction; and args_t
could be deduced from the 2nd function parameter args
, then it works fine.
BTW: Since C++20 we have std::type_identity
.