Function template argument deduction (class vs funtion template)

  • A+

Could you help me understand why the argument deduction works for the class template and does not work for the function template?

If I understand correctly, the class template defines a function, so when I call it is possible for the compiler to make an implicit cast, but in case of the function template, there is no function definition at the moment, so implicit cast not happening.

But I don't understand why the compiler can't create function definition and then apply implicit cast?

#include <functional>  template<typename ...ARGS> class Test1 { public:     void add(const std::function<void(ARGS...)>&) {} };  class Test2 { public:     template<typename ...ARGS>     void add(const std::function<void(ARGS...)>&) {} };  void func(int) {}  int main() {     Test1<int> test1;     test1.add(func);      Test2 test2;     test2.add<int>(func); } 

The error is:

In function 'int main()':

   25:24: error: no matching function for call to 'Test2::add(void (&)(int))'

   25:24: note: candidate is:

   14:10: note: template void Test2::add(const std::function&)

   14:10: note: template argument deduction/substitution failed:

   25:24: note: mismatched types 'const std::function' and 'void(int)'


In the first case, you are explicitly instantiating the class template Test1. This means the function declaration for its add member is generated with the signature add(const std::function<void(int)>&). When the compiler subsequently tries to resolve test1.add(func), there is only that one candidate. Since std::function<void(int)> can be implicitly constructed from a void(int) function, the signatures match, the compiler just instantiates the member function definition and everything is good.

In the second case, the compiler has to perform template argument deduction/substitution to see if it can "use" the add template. You may think that specifying int would nail down the template parameters so that no deduction is necessary, but that is not the case: It could be that you mean to partially specify template arguments, see for example here. In other words, you might be trying to instantiate the function template with more parameters than you specified explicitly, at least the compiler doesn't know if you do. So it still has to try and match the types of std::function<void(ARGS...)> (or more precisely, std::function<void(int, ...)> and void(int), which it can't, because implicit conversions are not considered for the deduction.

In short: Specifying explicit template arguments does not prevent template parameter deduction for variadic function templates.

Note: I am not 100% firm with the exact terminology, any language lawyering to correct me is appreciated!

Edit: I am basing this primarily on what I read here.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: