I'm working on code like following one
#include <functional>
template <typename Type>
void foo(const std::function<void(const Type&)> & handler) {}
void goo (const int&){}
int main() {
foo([](const int&){});
foo(goo);
}
unfortunate it refuses to compile on (clang 6.0.0 and gcc 8.1.1) due to following error
candidate template ignored: could not match 'function<void (const type-parameter-0-0 &)>' against '(lambda at test3.cpp:13:9)'
candidate template ignored: could not match 'function<void (const type-parameter-0-0 &)>' against '(lambda at test3.cpp:13:9)'
Is it possible to somehow force it to deduce Type
correctly?
You tagged C++17, so you can use deduction guides for std::function
's.
You can try something as follows
template <typename F,
typename Type = typename decltype(std::function{std::declval<F>()})::argument_type>
void foo (F f)
{
}
I know that argument_type
is deprecated in C++17, but you can substitute it with a simple custom template.
By example
template <typename>
struct firstArg;
template <typename R, typename A0, typename ... As>
struct firstArg<std::function<R(A0, As...)>>
{ using type = A0; };
and foo()
can be written as
template <typename F,
typename FUNC = decltype(std::function{std::declval<F>()}),
typename Type = typename firstArg<FUNC>::type>
void foo (F f)
{
}
This way the callable f
isn't a std::function
but it's original type (and this can be better or worse, depending from your exact requirements); if you need it in a std::function
, you can obtain it inside the foo()
function using again deduction guides or the FUNC
type
template <typename F,
typename FUNC = decltype(std::function{std::declval<F>()}),
typename Type = typename firstArg<FUNC>::type>
void foo (F f)
{
FUNC fnc{f};
}