Assume there is a template function foo()
which accepts an arbitrary number of arguments. Given the last argument is always an std::function
, how do I implement a foo()
template shown below in a way that CbArgs
would contain this std::function
's parameters?
template<typename... InArgs, typename... CbArgs = ???>
// ^^^^^^^^^^^^
void foo(InArgs... args) { ... }
For example, CbArgs
should be {int,int}
if invoked like this:
std::function<void(int,int)> cb;
foo(5, "hello", cb);
My first idea was:
template<typename... InArgs, typename... CbArgs>
void foo(InArgs... args, std::function<void(CbArgs...)>) { ... }
But this does not compile:
note: template argument deduction/substitution failed:
note: mismatched types ‘std::function<void(CbArgs ...)>’ and ‘int’
foo(5, "hello", cb);
Question One:
Why doesn't this compile? Why does the template argument deduction fail?
Eventually, I came up this solution:
template<typename... InArgs, typename... CbArgs>
void fooImpl(std::function<void(CbArgs...)>, InArgs... args) { ... }
template<typename... InArgs,
typename CbType = typename std::tuple_element_t<sizeof...(InArgs)-1, std::tuple<InArgs...>>>
void foo(InArgs... args)
{
fooImpl(CbType{}, args...);
}
Here CbType
is the last type in InArgs
which is std::function
. Then a temporary of CbType
is passed to fooImpl()
where CbArgs
are deduced. This works, but looks ugly to me.
Question Two:
I wonder if there is a better solution without having two functions and a temporary instance of CbType
?