Background:
Templates were added to C++ for the efficient implementation of generic algorithms and data structures. From the beginning, a mechanism for automatic type deduction from input arguments was needed to make template usage more convenient for developers.
The issue:
The deduction mechanism is not always straightforward: ambiguity arises with references, type masking, partial specializations, template parameters by reference, and constants. Sometimes the compiler cannot deduce the type or produces unexpected results.
The solution:
The compiler analyzes the arguments, matches them with template parameters, taking into account the rules of cv-qualifiers, references, and pointers. Limitations require explicit type specification when automatic deduction is not possible.
Code example:
template<typename T> void func(T arg) { /* ... */ } func(10); // T deduced as int func("abc"); // T deduced as const char* // The difference between T arg and T& arg: template<typename T> void printRef(T& arg); // Will not accept a temporary object!
Key features:
What happens if a template function takes T& and you try to pass it a temporary object?
The compiler will not be able to deduce the type, as a temporary object cannot be passed to a non-const reference. A compilation error will occur.
template<typename T> void foo(T& arg); foo(42); // Error!
How does type deduction work with arrays?
Arrays "decay" to pointers when passed by value, but if the template takes a reference, the array size is preserved, which is often used to implement safe-size templates.
template<typename T, size_t N> void arraySize(T (&arr)[N]) { std::cout << N; } int x[10]; arraySize(x); // Will output 10
Why is it not always correct to use auto for storing the results of template function calls?
Auto during type deduction can "slice" const or ref-qualifiers, which sometimes leads to unexpected copying or mutability errors.
auto x = funcReturningRef(); // x will be by value, not by reference!
A templated function for generic sorting takes T&, and the user tries to pass a temporary object. As a result, the code does not compile, and the error confuses the developer.
Pros:
Cons:
The sorter is implemented via universal references (T&&) using std::forward, allowing for proper handling of both lvalues and rvalues, thereby improving performance and flexibility.
Pros:
Cons: