Pure C ++: Generic programming with special templates

Source: Internet
Author: User

Pure C ++: Generic programming: Template specialization Release Date: 9/30/2005 | updated on: 9/30/2005

Stanley B. Lippman

As I mentioned in the previous column, the operations executed include not only simple storage and retrieval operations, but only the acceptable types that can be securely bound to them. [SeePure C ++: CLR generics Versus C ++ templates(English)]. When using generics, You can explicitly add these restrictions using the WHERE clause. In the C ++/CLI template tool, you can avoid these restrictions by specizing the function template or class template (a single member function or the entire class. For example, add the min function to the tstack class of the previous column. I usually use the regular min algorithm, but that algorithm is only useful when I am a programmer, and it is not helpful for me to write articles on Template specialization. For convenience,Figure 1The tstack class template definition is reproduced.

Figure 2Shows a possible implementation method of Min. I will define a local variable min_val to store the smallest element and initialize it as the first element of the container. Define two iterations and compare each element with min_val. If the value is smaller than min_val, the value is assigned again. Can you see the Implicit restrictions? If yes, you will get:

if ( *it < min_val )

Generally, for Min functions, only the types with built-in operators less than (<) or operator instances can be bound to elemtype. If a type does not define operator <(), and The tstack of this type of item calls min, the compile-time error will occur when invalid comparison operators are used in Min. For example, the system: string class is not smaller than the (<) operator (it uses the compareto method of icomparable ). Therefore, if I try to call min for tstack that uses string instantiation, it will encounter errors during compilation because the comparison operation fails.

There is a solution that I will not use: define the global Operator <(), which uses compareto to compare two string-type values. Then, tstack <string ^ >:: min () automatically calls these global operators:

bool operator<( String^ s1, String^ s2 ) {return ( s1->CompareTo( s2 ) < 0 ) ? true :false;}

Remember that the goal is to prevent tstack: min member function definition from being instantiated when the type parameter specified by the user is string, and you want to use the compareto method to define your tstack <string ^> :: min instance. You can use the explicit template special definition to provide special definitions for the Members instantiated by the class template to achieve this purpose. This definition specifies the Template Name, template parameters, function parameter list, and function body. The keyword template is followed by the less than (<) and greater than (>) tags, and then the class member special definition (seeFigure 3).

Even if the class type tstack <string ^> is defined from the general class template (that is, instances generated by the compiler for the string type, where each elemtype placeholder is replaced with the string type) every object of the tstack <string ^> type will call the special member function Min. Tstack: min member function definitions are neither extended nor used in tstack <string ^>.

In some cases, the entire class template definition may not be suitable for some type. In this case, programmers can provide a definition to specialize the entire class template. Programmers can define tstack <string ^>:

Template <class elemtype> ref class tstack; // class template special template <> ref class tstack <string ^> {public: tstack (); string ^ POP (); void push (stack ^ et );//...};

The explicit class template can be specialized only after the general class template is declared. If you provide complete class template specialization, you must define each member function or static data member associated with this specialization. The general member definitions of class templates cannot be used to create explicitly specialized member definitions, nor are they cross-checked. This is because the special class member set of the class template may be completely different from the class member set of the general template.

When defining fully specialized class templates (such as tstack <string ^>), do not add special template <> tags before the definition, you should explicitly list the actual types to specify the special definition, as shown below:

// Define the special class template // member function min () string ^ tstack <string ^ >:: min (){...}

Special partial templates

If a class template has multiple template parameters, You can specialize in one or more specific sets of parameterized values or types. That is to say, you may want to provide a template so that, except for some template parameters that have been replaced by actual types or actual values, they all match the regular template. This goal can be achieved by using the localized template specialization. For example, assume that the following buffer class template exists:

template <class elemType, int size>ref class Buffer { ... };

The following describes how to use local specialization for the buffer so that it can well process the buffer with a size of 1 kb:

// The local special template of the class template buffer <class elemtype> ref Class Buffer <elemtype, 1024 >{// use a special algorithm for the size of 1 kb ...};

The partial specialization of buffer has only one type parameter elemtype, because the size value is fixed to 1024. The list of parameters that are specific to a local template only lists parameters that are still unknown to the template parameters. However, when you define an instance of this template, you must specify the two parameters at the same time (this is different from using the default value for a parameter ). In the following example, a partial class template is instantiated using a type parameter with elemtype as string:

Buffer<String^,1024> mumble;

However, if you change to the following code line, the compiler will generate an error and mark the declaration as missing the second parameter:

Buffer <string ^> mumble; // Error

Why? What will happen if developers introduce a set of special buffer (as shown below?

template <class elemType>ref class Buffer<elemType,4096> {};template <class elemType> ref class Buffer<elemType,512> {};

If the second parameter is not required in the Declaration in the previous example, the compiler cannot differentiate these specializations!

The local specialization has the same name as the corresponding complete general template. In this example, It is buffer. This raises an interesting question. Note that the instantiation of buffer <string ^, 1024> can be performed either through the class template definition or through local specialization. So, why does it select local special to instantiate the template? The general rule is: if a local class template is declared as special, the compiler will select the most special template definition for instantiation. General template definitions are used only when local specialization is not available.

For example, when buffer <string ^, 2048> must be instantiated, the conventional template definition is selected because the instantiation does not match the special nature of any local template.

The definition of local specialization is completely different from that of conventional templates. Local specialization can have a group of Members that are completely different from conventional Class templates. The special member functions, static data members, and nested types of local class templates must have their own definitions, which are the same as those of class templates. The general definition of class template members cannot be used to instantiate special members of a local class template.

The local template specialization of class templates forms the basis for some very complex design idioms in modern c ++ usage. If you are interested in this, read Andrei Alexandrescu's 《Modern C++Design:Generic programming and design patterns applied(Addison-Wesley, 2001), learn more about this usage.

Function template Specialization

Non-member function templates can also be specialized. In some cases, you can take full advantage of some special knowledge about types to compile functions that are more efficient than functions instantiated from templates. In other cases, the definition of a regular template is incorrect for a certain type. For example, assume that you have the function template Max definition:

template <class T>T max( T t1, T t2 ) {return ( t1 > t2 ? t1 :t2 );}

If the system: string type template parameter is used to instantiate the function template, the generated instance cannot be compiled, because as you can see earlier, the string class cannot be smaller than (<) or greater than (>) operator.Figure 4The code in illustrates how to normalize the function template. (The general function template must be declared before it can be specialized .)

If template parameters can be inferred from function parameters, You can omit the limit Max of the actual type parameter in the explicit Special Declaration. <string ^>. For example, the compiler can push the T bound to the string in the following Max template specialization. Therefore, for convenience, this language allows the following shorthand notation:

// No problem: From the parameter type, it is inferred that t is bound to stringtemplate <> string ^ max (string ^, string ^). After this explicit specialization is introduced, the following calls will be resolved to this special instance: void Foo (string ^ S1, string ^ S2) {string ^ maxstring = max (S1, S2 ); //...}

If both parameters are of the string type, the regular function template does not extend. This is exactly what we need.

As long as an explicit function template is provided, you must always specify the template <> and function parameter list. For example, the following two declarations of Max are invalid and are marked:

// Error: Invalid Special Declaration // template missing <> string ^ max <string ^> (string ^, string ^ ); // The template of the function parameter list is missing <> string ^ max <string ^>;

In one case, omitting the special template of the function template is not an error. That is, when the declared common function has a list of return types and parameters that match the template instantiation:

// General template definition template <class T> T max (T T1, t T2) {/*... */} // No problem: normal function declaration! String ^ max (string ^, string ^ );

Without a doubt, you often feel helpless and think that C ++ is too hard to understand. You may want to know why everyone wants to declare a common function that matches the template instantiation, rather than making the sound more explicit and special. As shown in the following example, things are not done in exactly the way you like:

Void Foo (string ^ S1, string ^ S2) {// can I resolve a special instance? String ^ maxstring = max ("Muffy", S2 );//...}

In C ++/CLI, for the overload solution, the string text type is not only const char [N] [whereNIs the length of the text plus one (used to terminate null characters)], and is system: string. This means that given a group of functions

void f( System::String^ );     // (1)void f( const char* );         // (2)void f( std::string );         // (3)

Call as follows

// Parse it to (1) f ("bud, not buddy") in C ++/CLI ");

Exactly match (1), and under ISO-C ++, the resolution result will be (2 ). Therefore, the question is, is string text still processed as system: string for type inference of the function template? In short, the answer is "no ". (The detailed answer will be the topic of my next column, which will detail the function template .) Therefore, if you do not select a special string instance of Max, the next step is to call Max.

String ^ maxstring = max ("Muffy", S2); // Error

Compilation will fail, because the max definition requires that the two parameter types be T:

template <class T> T max( T t1, T t2 );

What can you do? Change the template to an instance with two parameters, as in the redeclaration below.

template <class T1,class T2> ??? max( T1 t1, T2 t2 );

This allows us to compile Max calls with Muffy and S2, but will be disconnected due to the greater than (>) operator and specify the parameter type to be returned.

All I want to do is to forcibly convert string text to the string type, which is also a method to save common functions.

If a parameter is used to deduce a template parameter, only a limited set of type conversions can be used to convert the parameters instantiated in the function template to the corresponding function parameter type. Another case is the explicit special function template. As you can see, the conversion from string text to system: String does not belong to the above situation.

Explicit specialization does not help avoid type conversion restrictions when harmful character strings exist. If you want to allow not only a limited set of type conversions, you must define common functions instead of function templates for specialization. This is why C ++ allows overloading of non-template functions and template functions.

I have basically finished speaking, but I still need to explain the last point. Create a groupFigure 5What does the max function mean? You know the call

max( 10, 20 );

It is always parsed as a regular template definition, and T is inferred as Int. Similarly, you still know that

max( "muffy", s2 );max( s2, "muffy" );

It will always be parsed as a normal function instance (where the text string is converted to system: string), but there is a problem that calls

max( s2, s2 );

Which of the three max functions will be parsed? To answer this question, we need to check the process of parsing the overloaded function.

Reload function parsing process

The first step for parsing overload functions is to create a candidate function set. The candidate function set contains the same name as the called function and can see the declared function during the call.

The first visible function is a non-template instance. I added this function to the candidate list. What about the Function template? When you can see the function template, If you can use function call parameters to instantiate the function, the template instantiation is considered as a candidate function. In my example, the function parameter is S2 and its type is string. The template parameter inference binds string to T, so the template instantiation max (string ^, string ^) will be added to the candidate function set.

Function template instantiation enters the candidate function set only when template parameter inference is successful. However, if the template parameter inference fails, no error will occur; that is, the function instantiation is not added to the candidate function set.

What if the template parameter is successfully inferred, but the template is a special parameter for the inferred template (as in my example? The result is that the explicit template is specialized (instead of defining the instantiated function through the regular template) and will enter the candidate function.

Therefore, this call has two candidate functions: Special template instantiation and non-template instances.

// Candidate functions // special templates... template <> string ^ max <string ^> (string ^ S1, string ^ S2); // non-template instance string ^ max (string ^, string ^ );

The next step for parsing overload functions is to select a feasible function set from the candidate function set. For a candidate function that is limited to a viable function, type conversion is required, and each actual parameter type is converted to the corresponding formal parameter type. In this example, both candidate functions are feasible.

The last step to resolve the overload function is to classify the type conversion applied by the parameter to select the best feasible function. For example, both functions look good. Since both functions are feasible, should this be regarded as an ambiguous call?

In fact, the call is clear: Non-template Max will be called because it takes precedence over template instantiation. The reason is that, to some extent, explicit functions are more practical than instances created using regular templates.

Surprisingly, I have completely eliminated the possibility of calling previous string specialization in solving harmful string text, so I can eliminate this problem. I only need regular template declarations and overloaded non-template instances:

// The final reload set template <class T> T max (T T1, t T2) supporting string ){/*... */} string ^ max (string ^, string ^ );

This is not necessarily complicated, but it is certain that, in terms of language integration and flexibility, it is far beyond the range supported by Common Language Runtime (CLR) generic functions.

Template specialization is the basis of C ++ template design. It provides the best performance, overcomes the limitations on individual or series classes, has a flexible design pattern, and has proven to be of great value in actual code. In the next column, I will thoroughly analyze C ++/CLI's support for template functions and general functions.

Please pass your questions and commentsPurecpp@microsoft.comSend to Stanley.

Stanley B. LippmanIs an architecture designer of Microsoft Visual C ++ team. He has been working with the c ++ designer Bjarne stroustrup at Bell Labs since 1984. Since then, he has made animations in Disney and DreamWorks, as well as senior advisor to JPL andFantasia 2000Software technical director.

Go to the original English page



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.