Rules

  1. Template argument deduction is done by comparing each function template parameter type with the type of the corresponding argument of the call.
  2. The function parameter type and function argument type do not have to match exactly. The following type conversions can be applied to the function argument to convert it to the type of the corresponding function parameter:
  3. If the same template parameter is found in more than one function parameter, the template argument deduced from each corresponding function argument must be the same type.
     #include <iostream>
        
     template<typename T>
     void foo(T, T){ std::cout << "foo was called" << std::endl; }
        
     int main(){
        double d = 1.0;
        foo(1, d); // error: no matching function for call to ‘foo(int, double&)’
        foo(1.0, d); // foo was called
        return 0;
     }
    

Example

  1. Only the parameters that actually depend on the template parameters participate in template argument deduction.
     #include <iostream>
    	
     template<typename T>
     void foo(T, int){ std::cout << "foo was called" << std::endl; }
    	
     int main(){
        double d = 1.0;
        foo(1, d); // foo was called
        return 0;
     }   
    
  2. template argument deduction/substitution failed: couldn’t deduce template parameter U.
    #include <iostream>
    	
    template<typename T, typename U>
    void foo(T){ }
    	
    int main(){
       foo(2);
       return 0;
    }
    
  3. Summary (14.8.2.1 Deducing template arguments from a function call [temp.deduct.call]):

    template void func1(T param) { std::cout << std::is_const::value << std::is_reference::value << '\n'; }

    template void func2(const T param) { std::cout << std::is_const::value << std::is_reference::value << '\n'; }

    template void func3(T& param) { std::cout << std::is_const::value << std::is_reference::value << '\n'; }

    template void func4(const T& param) { std::cout << std::is_const::value << std::is_reference::value << '\n'; }

    int main() { int i = 42; int& ri = i; const int ci = 100; const int& cri = ci;

    func1(i);    // 00
    func1(ci);   // 00
    func1(ri);   // 00
    func1(cri);  // 00
     
    func2(i);    // 00
    func2(ci);   // 00
    func2(ri);   // 00
    func2(cri);  // 00
     
    func3(i);    // 00
    func3(ci);   // 10
    func3(ri);   // 00
    func3(cri);  // 10
     
    func4(i);    // 00
    func4(ci);   // 00
    func4(ri);   // 00
    func4(cri);  // 00 } ```