Real-Time Parameter deduction for templates

**1. What is real parameter deduction?**

If we must explicitly specify the template replacement parameter type every time, such as concat <std: string, int> (s, 3), the process will be very cumbersome. If we can concat (s, 3) // We must declare that s is of the std: string type, it will be as simple as calling a common function. In fact, C ++ allows such writing, and then the C ++ compiler will calculate the appropriate replacement type based on the real parameters (s and 3. How to interpret it?

1 template<typename T>2 T const& max(T const& a T const& b)3 {4 return a < b ? b : a;5 }6 7 int g = max(1, 1.0);

The above deduction will fail. Why? Because

**"Parameter type T corresponding to the function template"**There is only one,

**"Call real parameter type"**(Int and double are the types 1 and 1.0), which may lead to deduction conflicts and thus fail. Another failure is that the replacement type causes an invalid structure. As follows:

1 template <typename T> 2 typename T: ElementT at (T const & a, int I) 3 {4 return a [I]; 5} 6 7 void f (int * p) 8 {9 int g = at (p, 1); // The deduction fails because T is interpreted as T *, but int * does not have a replacement type called ElementT. 10}

**Ii. Flexible replacement rules**For the convenience of the following description, we agree that the type from the called real parameter type is

**Matching type**From

**Parameter type T corresponding to the function Template**Is

**Matching type P**
**(1) If the declared parameter is a declaration with reference (T & or T const &), then the matching type P (T or T const ), A is still A real parameter type, no**
**The high-level const and volatile qualifiers are ignored.**
**(2)**
**If the declared parameter is a non-reference declaration,**
**P is the declared parameter type (such as T *), and A is still the real parameter type,**
**The high-level const and volatile limits are ignored.**
**(3)**
**If the declared parameter is a non-reference declaration,**
**If this real Parameter**If it is an array or a function type (function pointer), the decay conversion will occur, convert it to the corresponding pointer type, and ignore the high-level const and volatile qualified symbols. (4) Real parameter 7 cannot be passed to int &

Template <typename T> void f (T); // P is Ttemplate <typename T> void g (T &); // P is Tdouble x [20]; int const seven = 7; f (x); // T is interpreted as double *, and decay is converted to g (x ); // T is interpreted as double [20] f (seven); // T is interpreted as int, ignoring the high-level constg (seven ); // T is interpreted as int const, and f (7) is not ignored; // T is interpreted as intg (7); // T is interpreted as int, but 7 cannot be passed to int &

(5) another pitfall: if the real parameter is a string, the result T should be a string array, not a string pointer char *

template<typename T>T const& max(T const& a, T const& b);

Max ("Apple", "Pear"); the "Apple" type is char const [6], and the "Pear" type is char const [5]; there is no decay transformation from an array to a pointer (because the deductive parameter is a reference parameter ). Therefore, to make the deduction successful, T must be both char [6] and char [5]. This is obviously impossible, so errors are generated.

**Iii. Hands-on training**

Template <typename T> void f1 (T *); template <typename E, int N> void f2 (E (&) [N]); template <typename T1, typename T2, typename T3> void f3 (T1 (T2: *) (T3 *); class S {public: void f (double *);}; void g (int *** ppp) {bool B [42]; f1 (ppp); // assume T is int *** f2 (B ); // assume that E is bool, N is 42 f3 (& S: f); // assume that T1 is void, T2 is S, and T3 is double}

The process of deduction of Context: matching starts from the top layer, and then continuously recursion various composition elements. However, two types of constructor cannot be used to interpret context. (1) Restricted

**Type**Name, Q <T>: The type name of X cannot be used to deduce the template parameter T (2) In addition to non-type parameters, the template parameter also contains non-type expressions of other components, such as S <I + 1>, int (&) [sizeof (S <T>)] type cannot be used

**Deduction**I and T why? Because the deduction process is not unique (or even not necessarily limited ).

template<int N>class X{public: typedef int I; void f(int){}};

If you use**Int**Deduction**Typename X <N >:: I**, So it is not successful, why is there a lot**X <1>: I, X <2>: I, X <3>: I ...... X <1000>: I**C ++ prohibits such deduction.

Template <int N> void fppm (void (X <N >:: * p) (typename X <N >:: I); int main () {fppm (& X <33 >:: f); // the deduction is successful, N = 33}

In the function template fppm (), the sub-constructor X <N >:: I is not a deductive context, but can use the member pointer type (X <N >:* p) the member section X <N> assumes the context.

**Iv. Deduction in special circumstances**There are two cases, where the deduction of the real parameter-parameter pair (A, P) is not from the real parameters of the function call, function template parameters.

template<typename T>void f(T, T);void (*pf)(char, char) = &f;

(1) The first case is:

**When getting the address of the function template,**A is void (char, char), P is void (T, T), T is interpreted as char, at the same time, pf is initialized as the address of "special f <char>" ---------------------- I am a gorgeous split line (￣ ------------------------------------

Class S {public: template <typename T, int N> operator T [N] & (); // I am a transformation operator and convert it to the T [N] type }; void f (int (&) [20]); // The parameter type is 20 RMB array void g (S) {f (s );}

We try to convert S to int (&) [20]; so type A is int (&) [20], type P is T [N], so replace T with int, replace N with 20. The deduction type is successful.

**V. Flexible replacement rules**(1) For the template parameter-real parameter pair (P, A), there are two cases where P can have one more const or volatile qualifier than. ① If the declared parameter is A reference parameter subparameter, the P type can have one more const or volatile than the type. ② It doesn't matter if the original declared parameter is A reference parameter subparameter, if the type is A pointer or A member pointer, the P type can have one more const or volatile than the type. (2) When the deduction process does not involve the transformation operator template, the replaced P type can be A base class of the type, or when A is A pointer type, P can be A pointer type, and P points to the base class of the type pointed to by A. This loose match will only occur if the exact match is not found.

Template <typename T> class B {}; template <typename T> class D: public B <T> {}; template <typename T> void f (B <T> *); void g (D <long> dl) {f (& dl); // success, replace T with long}

**Vi. Warning: class template parameters cannot be used for real parameter deduction**
** **
**VII. Warning: the default real parameters in the function template cannot be used for real parameter deduction, even if the real parameters are not dependent real parameters**
Template <typename T> void f (T x = 42) {} int main () {f <int> (); // correct, instantiate f (); // error, cannot be used for real-argument deduction}

**8. A tricky Barton-Nackman Method**At that time, this method was created for the following reasons: (1) function templates cannot be overloaded at that time (2) operator = If the overload is in the class template, based on the above flexible conversion methods (pointing to the base class, pointing to the cloud of the subclass), the first real parameter (pointing to this pointer), the transformation rules of the second real parameter may be different. Now define a template class Object. If you want to define operator = for this class, the operator = cannot be defined inside the class (according to (2 )), you cannot define namespaces outside the global or class, for example, template <typename T> bool operator = (Array <T> const & a, Array <T> const & B) {......}, (According to (1) Barton and Nackman define this operator as a normal friend function of the class within the class. As follows:

# Include <iostream> using namespace std; template <typename T> class Object {public: int a; Object (int n): a (n) {} friend bool operator = (Object <T> const & lt, Object <T> const & rt) {return equal (lt, rt ); // call the overloaded function based on the parameter type }}; bool equal (Object <int> const & lt, Object <int> const & rt) // This is a common function, can be reloaded. {return lt. a = rt. a;} int main () {Object <int> s (1); Object <int> s1 (1); cout <(s = s1) <endl; return 0 ;}

Finally, the program is successfully compiled and runs successfully.

Note: The runtime environments of these codes are all carried out under mingw. VS2013 estimates that it has re-implemented the Template Name Search. Many books say that the name cannot be found, VS2013 finds (-_-) B, so in order to better learn C ++ Templates and switch to MinGW, the editor is codeblocks. Edit: Claruarius. For more information, see the source.

Omitting the real parameters of the C ++ Template

First case: template <typename T> void fun (T const & a, T const & B); but it is fun (250,250.4) when you call it ); then you must write it as fun <int> (250,250.4 );

Scenario 2: template <typename T, typename RT> RT fun (T const & a, T const & B); there is no way to perform deduction at this time, therefore, you can rewrite the template <typename RT, typename T> RT fun (T const & a, T const & B); when calling it, write it as fun <double> );

The fourth type is template <typename T> void fun (). The call is fun ()!!

Omitting the real parameters of the C ++ Template

Template class T

Function return type function name ()

The angle brackets contain the template parameters, and the following parentheses contain the real parameters of the template function.

Please visit wenku.baidu.com/...0.html.