I have the following code:
#include <iostream>
#include <functional>
template<typename Return, typename... Params>
void func(std::function<Return(Params... )> x) {}
void f(double) {}
int main() {
//func<void, double>(f); // compile error here in the variadic case
func(std::function<void(double)>(f));
}
I have 2 questions:
1.
I do not understand why does the line func<void, double>(f);
give me a compiling error
/Users/vlad/minimal.cpp:10:5: error: no matching function for call to 'func'
func<void, double>(f); // compile error here in the variadic case
^~~~~~~~~~~~~~~~~~
/Users/vlad/minimal.cpp:5:6: note: candidate template ignored: could not match 'function<void (double, type-parameter-0-1...)>' against 'void (*)(double)'
void func(std::function<Return(Params... )> x) {}
^
1 error generated.
whereas if I cast the parameter f
to a std::function
(as in the non-commented line) it works.
2.
And the most puzzling issue is that, if I use a non-variadic version of func
(i.e. just replace typename...
by typename
so in effect func
takes a std::function<Return(Params)>
as parameter), then the commented line in main
works as desired. Any ideas why?
The compiler doesn't know that you want
Params
to be exactlydouble
, it thinks maybe you want it to deduce a pack with more elements, such asdouble, int, void*, char
ordouble, double, double
or some other pack of types, and it doesn't know how to deduce that from the argumentf
.In theory there could be other specializations of
std::function
which could be constructible fromf
and which would allow the compiler to deduce a pack of more than one type forParams
(it can't know that isn't true without instantiating every possible specialization ofstd::function
and testing them, which is not feasible.Because now the compiler is able to deduce
Params
correctly.Because now the compiler knows that
Params
is a single type, not a pack of zero or more types, so when you sayfunc<void, double>
it knowsParams
isdouble
, and notdouble, int, void*, char
or some other parameter pack.Edit in answer to your comment, consider this:
I've only given an explicit template argument for two of the parameters, so the third must still be deduced.
When you have a variadic template there could be any number of other parameters remaining to be deduced.