Templates
Templates
Function Templates |
Introduction |
In previous programs, we found out that we could pass any type of value, based on one of the primitive data types, to the WriteLine() method of the Console class and it would appropriately display the value. Here are examples:
using namespace System; // Display the value of an integer void Show(int value) { Console::WriteLine(value); } // Display the value of a double-precesion value void Show(double value) { Console::WriteLine(value); } // Display the value of a character void Show(__wchar_t value) { Console::WriteLine(value); } int main() { // Call the version of the function that displays an integer Show(246); // Call the version of the function that displays a character Show('G'); // Call the version of the function that displays a decimal Show(355.65); return 0; }
This would produce:
246 G 355.65 Press any key to continue . . .
We passed a constant value directly to the function when we called it. Remember that you can also first declare a variable, assign it a value, and then pass that variable to the function. Here are examples:
int main() { // Call the version of the function that displays an integer int Value1 = 246; Show(Value1); // Call the version of the function that displays a character __wchar_t Value2 = L'G'; Show(Value2); // Call the version of the function that displays a decimal double Value3 = 355.65; Show(Value3); return 0; }
Although this is based on the concept of function overloading, another way you can solve this type of problem is to create one function that doesn't know the type of value that would be passed to it but the function is equipped to process the value appropriately. Based on the above program, you can create one function that takes an argument and it displays its value. To do this, at the time you are defining the function, you only let it know that it would receive an argument but you don't specify the type of value that it will process. This the basis of templates in C++.
Practical Learning: Introducing Templates |
#include <iostream> using namespace std; typedef double ItemType; struct CItem { ItemType Item; CItem *Next; }; CItem * Head = NULL; int Size; int Count() { return Size; } int Add(CItem * NewItem) { CItem * Sample = new CItem; Sample = NewItem; Sample->Next = Head; Head = Sample; return Size++; } CItem * Retrieve(int Position) { CItem * Current = Head; for(int i = Count() - 1; i > Position && Current != NULL; i--) { Current = Current->Next; } return Current; } void ShowItem(ItemType item) { cout << "Item: " << item << endl; } int main() { CItem * Part; Part = new CItem; Part->Item = 97.43; Add(Part); Part = new CItem; Part->Item = 274.87; Add(Part); Part = new CItem; Part->Item = 8.7873; Add(Part); Part = new CItem; Part->Item = 2764.4; Add(Part); Part = new CItem; Part->Item = 92.4662; Add(Part); Part = new CItem; Part->Item = 66800.85; Add(Part); cout << "-=- List of Items -=-" << endl; for(int i = 0; i < Count(); i++) { CItem * One = Retrieve(i); ShowItem(One->Item); } cout << "\nNumber of Items: " << Count() << "\n\n"; return 0; }
-=- List of Items -=- Item: 97.43 Item: 274.87 Item: 8.7873 Item: 2764.4 Item: 92.4662 Item: 66800.9 Number of Items: 6 Press any key to continue . . .
A template function is a function that can process a value whose type is known only when the variable is accessed. To create a function template, use the following formula:
template <class Parameter> ReturnType FunctionName(Argument(s)) { }
The template keyword, the class keyword, the <, and the > operators are required. On the right side of the class keyword, type a name that follows the rules of names in C++. Most programmers simply use the letter T. In our example, we use the Parameter name. After that, define the function as we have done so far. Here is an example:
template <class TypeOfValue> void Show() { }
In our lesson and in the examples, the Parameter factor will be referred to as template parameter or parameter type and sometimes simply as parameter.
Passing the Template Parameter as Argument |
To indicate that the function will process a value that is based on the parameter, that is, the type on the right side of the class keyword, you should pass it as argument to the function. You do this by preceding the name of the argument with the Parameter factor. Here is an example:
template <class TypeOfValue> void Show(TypeOfValue Argument) { }
In the body of the function, you can then process the Parameter as you see fit. At a minimum, and based on our earlier program, you can simply display the value by passing it to the Console::WriteLine() method. Here is an example:
template <class TypeOfValue> void Show(TypeOfValue value) { Console::WriteLine(value); }
Practical Learning: Creating a Function Template |
template <class T> void ShowItem(T item) { cout << "Item: " << item << endl; }
Calling a Function Template |
As mentioned earlier, one of the particularities of a function template is that, at the time it is defined, the function doesn't know the type of the parameter. This means that, when calling the function, you must make sure you clearly specify the type of value that will be processed. You can do this by directly passing (a constant of) the type of value that the function will process. Here are different examples of calling our Show() function:
using namespace System; template <class TypeOfValue> void Show(TypeOfValue value) { Console::WriteLine(value); } int main() { // Call the function and pass it an integer value Show(246); // Call the function and pass it a character value Show(L'G'); // Call the function and pass it a double-precision value Show(355.65); return 0; }
When complied and executed, this program would produce:
246 71 355.65 Press any key to continue . . .
As an alternative, you can type the name of the function, followed by angle brackets. Inside of the brackets, enter the data type of the value that will be processed. After the angle brackets, open the parentheses and, inside of them, type the constant value that will be processed. Here are examples:
using namespace System; template <class TypeOfValue> void Show(TypeOfValue value) { Console::WriteLine(value); } int main() { // Call the function and pass it an integer value Show<int>(246); // Call the function and pass it a character value Show<__wchar_t>(L'G'); // Call the function and pass it a double-precision value Show<double>(355.65); return 0; }
Remember that you can also first declare a variable, assign it a value, and then pass that variable to the parentheses of the function. Here are examples:
using namespace System; template <class TypeOfValue> void Show(TypeOfValue &value) { Console::WriteLine(value); } int main() { // Call the function and pass it an integer value int a = 246; Show<int>(a); // Call the function and pass it a character value __wchar_t u = L'G'; Show<__wchar_t>(u); // Call the function and pass it a double-precision value double x = 355.65; Show<double>(x); return 0; }
You can also declare the value as a constant before passing it to the function.
Function Templates and Pointers |
A Template Parameter as a Reference |
As you can use references for a regular variable, you can create a template function parameter as a reference. To do this, in the parentheses of the function, precede the name of the parameter with the & operator. Here is an example:
template <class TypeOfValue> void Show(TypeOfValue &value) { Console::WriteLine(value); }
When calling the function, make sure you pass the argument as a reference. Here are examples:
using namespace System; template <class TypeOfValue> void Show(TypeOfValue &value) { Console::WriteLine(value); } int main() { // Call the function and pass it an integer value int a = 246; int &b = a; Show<int>(b); // Call the function and pass it a character value __wchar_t u = L'G'; __wchar_t &v = u; Show<__wchar_t>(v); // Call the function and pass it a double-precision value double x = 355.65; double &y = x; Show<double>(y); return 0; }
A Template Parameter as a Pointer |
Instead of declaring a template parameter as a regular type, you can create it as a pointer. To do this, precede the Argument factor with an asterisk. Remember that, when using the parameter, you must process it as a pointer. Here is an example:
template <class TypeOfValue> void Show(TypeOfValue *value) { Console::WriteLine(*value); }
When calling the function, apply the rules of pointers passed to functions. Here are examples:
using namespace System; template <class TypeOfValue> void Show(TypeOfValue *value) { Console::WriteLine(*value); } int main() { // Call the function and pass it an integer value int a = 246; Show<int>(&a); // Call the function and pass it a character value __wchar_t u = L'G'; Show<__wchar_t>(&u); // Call the function and pass it a double-precision value double x = 355.65; Show<double>(&x); return 0; }
Remember that you can first declare a pointer variable, initialize it, and then pass it to the function. Here are examples:
using namespace System; template <class TypeOfValue> void Show(TypeOfValue *value) { Console::WriteLine(*value); } int main() { // Call the function and pass it an integer value int *a = new int(246); Show<int>(a); // Call the function and pass it a character value __wchar_t *u = new __wchar_t(L'G'); Show<__wchar_t>(u); // Call the function and pass it a double-precision value double *x = new double(355.65); Show<double>(x); return 0; }
A Template Parameter as a Handle |
If you declare a variable as a regular value, it would be stored in the stack. If you declare it as a pointer, it would be stored in the native heap. If you want to process a variable in the managed heap, create it as handle, applying the rules we have learned in previous lessons. For a template, pass the parameter as a handle. If you want to display it on the console, pass its pointer to the Console::WriteLine() method. This can be done as follows:
using namespace System; template <class TypeOfValue> void Show(TypeOfValue ^ value) { Console::WriteLine(value); }
Before calling the method, make sure you have created a variable as a handle and pass it to the function. This would be done as follows:
int main() { // Call the function to display the number of pages of a book int ^ a = gcnew int(704); Console::Write(L"Number of Pages: "); Show<int>(a); // Call the function to display the character gender __wchar_t ^ u = gcnew __wchar_t(L'M'); Console::Write(L"Employee Gender: "); Show<__wchar_t>(u); // Call the function to display somebody's hourly salary double ^ x = gcnew double(18.48); Console::Write(L"Hourly Salary: "); Show<double>(x); return 0; }
As you should know already, you can pass a handle to String to the Console::WriteLine() method to display on the console. In the same way, you can pass a String value to a template function. Here is an example:
using namespace System; template <class TypeOfValue> void Show(TypeOfValue ^ value) { Console::Write(value); } int main() { // Call the function to display the number of pages of a book String ^ strMessage = L"Number of Pages: "; int ^ a = gcnew int(704); Show(strMessage); Show(a); Console::WriteLine(); // Call the function to display the character gender strMessage = L"Employee Gender: "; __wchar_t ^ u = gcnew __wchar_t(L'M'); Show(strMessage); Show(u); Console::WriteLine(); // Call the function to display somebody's hourly salary strMessage = L"Hourly Salary: "; double ^ x = gcnew double(18.48); Show(strMessage); Show<double>(x); Console::WriteLine(); return 0; }
This would produce:
Number of Pages: 704 Employee Gender: M Hourly Salary: 18.48 Press any key to continue . . .
A Function Template With Various Parameters |
Just like a function can take one argument, it can take various template parameters. You can pass one argument as a known type and the other as a template parameter. Here is an example:
using namespace System; template <class TypeOfValue> void Show(String ^ msg, TypeOfValue value) { Console::WriteLine(L"{0}: {1}", msg, value); } int main() { // Call the function and pass it an integer value Show(L"Integer", 246); // Call the function and pass it a character value Show(L"Character", 'G'); // Call the function and pass it a double-precision value Show(L"Decimal", 355.65); return 0; }
This would produce:
Integer: 246 Character: 71 Decimal: 355.65 Press any key to continue . . .
In the same way, you can pass different parameters to the function, and you can pass different known types and different parameter types, in any order of your choice.
Although we directly passed the values to the function when calling it, you can first declare a variable before passing it to the function. Here are examples:
using namespace System; template <class TypeOfValue> void Show(String ^ msg, TypeOfValue value) { Console::WriteLine(L"{0}: {1}", msg, value); } int main() { // Call the function and pass it an integer value const int iValue = 246; Show(L"Integer", iValue); // Call the function and pass it a character value const __wchar_t cValue = L'G'; Show(L"Character", cValue); // Call the function and pass it a double-precision value const double dValue = 355.65; Show(L"Decimal", dValue); return 0; }
The other concepts we have reviewed so far are still valid. For example, you can pass the parameter by value, by reference, as a pointer, as a constant reference, or as a constant pointer. Here is the parameter passed as a constant reference:
template <class TypeOfValue> void Show(String ^ msg, const TypeOfValue &value) { Console::WriteLine(L"{0}: {1}", msg, value); }
You can also involve the argument in conditional statements as you see fit.
Class Templates |
Introduction |
Like a function, a class can be created as a template. In fact, the class is more flexible than the function. To create a class template that uses a constant value for the parameter, use the following formula:
template <PrimitiveDataType ParameterName> Options class ClassName { }
The template and class keywords are required, so are the < and the > operators. Also, the curly brackets that delimit a class must be specified. The Options factor can be an appropriate combination of public, private, ref, and/or value keywords. The class keyword is followed by the name of the class, followed by the delimiting curly brackets of a class.
Practical Learning: Introducing Class Templates |
#pragma once typedef double ItemType; public value struct CItem { ItemType Item; CItem ^ Next; }; public ref class CListOfItems { private: int Size; public: // List Initialization CListOfItems(void); CItem ^ Head; // List Finalization ~CListOfItems(); !CListOfItems(); // Operations on list int CListOfItems::Count(); int CListOfItems::Add(CItem ^ item); CItem ^ CListOfItems::Retrieve(int Position); };
#include "ListOfItems.h" CListOfItems::CListOfItems(void) : Head(nullptr), Size(0) { } CListOfItems::~CListOfItems() { delete Head; } CListOfItems::!CListOfItems() { } int CListOfItems::Count() { return Size; } int CListOfItems::Add(CItem ^ NewItem) { CItem ^ Sample = gcnew CItem; Sample = NewItem; Sample->Next = Head; Head = Sample; return Size++; } CItem ^ CListOfItems::Retrieve(int Position) { CItem ^ Current = Head; for(int i = Count() - 1; i > Position && Current != nullptr; i--) { Current = Current->Next; } return Current; }
#include "ListOfItems.h" using namespace System; int main() { CListOfItems ^ Items = gcnew CListOfItems; CItem ^ Part; Part = gcnew CItem; Part->Item = 97.46; Items->Add(Part); Part = gcnew CItem; Part->Item = 8844.82; Items->Add(Part); Part = gcnew CItem; Part->Item = 108.7873; Items->Add(Part); Part = gcnew CItem; Part->Item = 2764.48; Items->Add(Part); Part = gcnew CItem; Part->Item = 70062.83; Items->Add(Part); Console::WriteLine(L"-=- List of Items -=-"); for(int i = 0; i < Items->Count(); i++) { CItem ^ One = Items->Retrieve(i); Console::WriteLine(L"Item: {0}", One->Item); } Console::WriteLine(L"\nNumber of Items: {0}\n", Items->Count()); return 0; }
A Template Parameter as a Constant Type |
When creating a class template using our formula, the PrimitiveDataType factor must be one of the integer data types built in the C++ language (short, Byte, char, __wchar_t, etc). It cannot be a floating-point type (float, Single, or double). The data type is followed by a name for the parameter. Outside of the > operator, you can specify such factors as the public, the private, the value, and/or the ref keywords, following the same rules applied to the creation of a class in the previous lessons.
Here is an example of a class:
template <__wchar_t c> public ref class Description { public: Description(); Description(__wchar_t msg) { } ~Description(); void Show(); };
It's important to remember that, with this class creation, the c parameter is a constant. If you define a method in the body of the class, you can use the template parameter as you see fit. Here is an example:
template <__wchar_t c> public ref class Description { public: Description(); Description(__wchar_t msg) { } ~Description(); void Show(); };
If you implement a method outside of the body of the class, precede it with the declaration of
template <PrimitiveDataType ParameterName>
Then, after typing the name of the class and before the :: operator, enclose the parameter name within the < and > operators. Here is an example:
template <__wchar_t c> Description<c>::Description() { }
When processing the class, you can involve the template parameter as you want. For example, you can pass it to the (cout class or the) Console::WriteLine() method to display it in the console. You can also involve the parameter in an appropriate operation, such as checking it using a conditional operator. Here is an example:
template <__wchar_t c> void Description<c>::Show() { switch(c) { case L'i': case L'I': Console::WriteLine(L"Integer"); break; case L'c': case L'C': Console::WriteLine(L"Character"); break; case L'f': case L'F': case L'd': case L'D': Console::WriteLine(L"Decimal"); break; } }
Because the template parameter is treated as a constant, you can formally declare it using the const keyword.
Class Template Declaration |
After creating a class template, you can use it by primarily declaring a variable. To declare a variable of a class template in the stack, you can use the following formula:
ClassName<ValueType> VariableName;
The < operator, the > operator, and the ; are required. Like any declaration, you start with the name of the type, in this case the name of the class. Between the angle brackets, specify the same primitive type you used when creating the class. End the stack declaration by the name of the variable. After this declaration, you can use the variable as you see fit. Here is an example:
using namespace System; template <__wchar_t c> public ref class Description { public: Description(); Description(__wchar_t msg) { } ~Description(); void Show(); }; template <__wchar_t c> Description<c>::Description() { } template <__wchar_t c> Description<c>::~Description() { } template <__wchar_t c> void Description<c>::Show() { switch(c) { case L'i': case L'I': Console::WriteLine(L"Integer"); break; case L'c': case L'C': Console::WriteLine(L"Character"); break; case L'f': case L'F': case L'd': case L'D': Console::WriteLine(L"Decimal"); break; } } int main() { // Call the function and pass it an integer value Description<L'i'> iDscr; iDscr.Show(); // Call the function and pass it a character value Description<L'c'> cDscr; cDscr.Show(); // Call the function and pass it a double-precision value Description<L'f'> dDscr; dDscr.Show(); return 0; }
You can also declare the class variable on the managed heap. To create a handle for the class, in both sides of the assignment operator, type the name of the class followed by the < operator, the type of value, and the > operator. Remember that, for a handle, you must use the ^ and the gcnew operators. Here are two examples:
int main() { // Call the function and pass it an integer value Description<L'i'> iDscr; iDscr.Show(); // Call the function and pass it a character value Description<L'c'> ^ cDscr = gcnew Description<L'c'>; cDscr->Show(); // Call the function and pass it a double-precision value Description<L'f'> ^ dDscr = gcnew Description<L'f'>(L'f'); dDscr->Show(); return 0; }
A Class Template of an Unknown Type |
As done for a function, you can create a template without specifying the type of value it would hold. You can declare a member variable of an unknown type. You can pass an unknown type to the methods of a class. To create such a class template, you can use the following formula:
template <class Type> Options class ClassName { }
Once again, the template and class keywords are required, so are the < and the > operators. Inside the <>, after the class keyword, enter a name for the template. The Options factor can be an appropriate combination of public, private, ref, and value keywords. After the name of the class, represented in our formula as ClassName, delimit the body of the class with the curly brackets. In the body of the class, you can do whatever you judge necessary. You can declare a member variable as a template type. You can pass an argument as a template type to one or more of the methods. Here is an example of a class:
template <class TypeOfValue> public ref class Description { public: Description(); Description(TypeOfValue type); ~Description(); void Show(); String ^ Message; TypeOfValue Value; };
If you define a method in the body of the class, you can use the member variable as you see fit. Here is an example:
template <class TypeOfValue> public ref class Description { public: Description(); Description(TypeOfValue type) : Value(type) { } ~Description(); void Show(); String ^ Message; TypeOfValue Value; };
As mentioned earlier, if you want to define a method outside of the body of the class, precede it with the declaration of
template <class Type>
After typing the name of the class and before the :: operator, enclose the template type within the < and > operators. Here is an example:
template <class TypeOfValue> Description<TypeOfValue>::Description() { }
In both cases, whether defining the method in the body of the class or outside, use the member variable. Here is an example:
template <class TypeOfValue> void Description<TypeOfValue>::Show() { Console::WriteLine(L"{0}: {1}", Message, Value); }
You can declare a variable of a class template the same way we saw earlier, in the stack or in the managed heap. Here are examples:
using namespace System; template <class TypeOfValue> public ref class Description { public: Description(); Description(TypeOfValue type) : Value(type) { } ~Description(); void Show(); String ^ Message; TypeOfValue Value; }; template <class TypeOfValue> Description<TypeOfValue>::Description() { } template <class TypeOfValue> Description<TypeOfValue>::~Description() { } template <class TypeOfValue> void Description<TypeOfValue>::Show() { Console::WriteLine(L"{0}: {1}", Message, Value); } int main() { // Call the function and pass it an integer value // Declare the variable on the stack heap Description<int> iDscr; iDscr.Value = 246; iDscr.Message = L"Integer"; iDscr.Show(); // Call the function and pass it a character value // Declare the variable on the managed heap Description<__wchar_t> ^ cDscr = gcnew Description<__wchar_t>; cDscr->Value = 'G'; cDscr->Message = L"Character"; cDscr->Show(); // Call the function and pass it a double-precision value // Declare the variable on the managed heap Description<double> ^ dDscr = gcnew Description<double>(355.65); dDscr->Message = L"Decimal"; dDscr->Show(); return 0; }
Practical Learning: Using a Non-Integer Template Argument |
#pragma once template <class T> public value struct CItem { T Item; CItem ^ Next; }; public ref class CListOfItems { private: int Size; public: // List Initialization CListOfItems(void); CItem<double> ^ Head; // List Finalization ~CListOfItems(); !CListOfItems(); // Operations on list int CListOfItems::Count(); int CListOfItems::Add(CItem<double> ^ item); CItem<double> ^ CListOfItems::Retrieve(int Position); };
#include "ListOfItems.h" CListOfItems::CListOfItems(void) : Head(nullptr), Size(0) { } CListOfItems::~CListOfItems() { delete Head; } CListOfItems::!CListOfItems() { } int CListOfItems::Count() { return Size; } int CListOfItems::Add(CItem<double> ^ NewItem) { CItem<double> ^ Sample = gcnew CItem<double>; Sample = NewItem; Sample->Next = Head; Head = Sample; return Size++; } CItem<double> ^ CListOfItems::Retrieve(int Position) { CItem<double> ^ Current = Head; for(int i = Count() - 1; i > Position && Current != nullptr; i--) { Current = Current->Next; } return Current; }
#include "ListOfItems.h" using namespace System; int main() { CItem<double> ^ item; CListOfItems ^ Items = gcnew CListOfItems; item = gcnew CItem<double>; item->Item = 97.46; Items->Add(item); item = gcnew CItem<double>; item->Item = 8844.82; Items->Add(item); item = gcnew CItem<double>; item->Item = 108.7873; Items->Add(item); item = gcnew CItem<double>; item->Item = 2764.48; Items->Add(item); item = gcnew CItem<double>; item->Item = 70062.83; Items->Add(item); Console::WriteLine(L"-=- List of Items -=-"); for(int i = 0; i < Items->Count(); i++) { CItem<double> ^ One = Items->Retrieve(i); Console::WriteLine(L"Item: {0}", One->Item); } Console::WriteLine(L"\nNumber of Items: {0}\n", Items->Count()); return 0; }
-=- List of Items -=- Item: 97.46 Item: 8844.82 Item: 108.7873 Item: 2764.48 Item: 70062.83 Number of Items: 5 Press any key to continue . . .
We have seen that a template could be created using the class keyword. As an alternative, you can use the typename keyword instead of class. Here is an example:
using namespace System; template <typename TypeOfValue> public ref class Description { public: Description(); Description(TypeOfValue type) : Value(type) { } ~Description(); void Show(); String ^ Message; TypeOfValue Value; }; template <typename TypeOfValue> Description<TypeOfValue>::Description() { } template <typename TypeOfValue> Description<TypeOfValue>::~Description() { } template <typename TypeOfValue> void Description<TypeOfValue>::Show() { Console::WriteLine(L"{0}: {1}", Message, Value); } int main() { // Call the function and pass it an integer value // Declare the variable on the stack heap Description<int> iDscr; iDscr.Value = 246; iDscr.Message = L"Integer"; iDscr.Show(); // Call the function and pass it a character value // Declare the variable on the managed heap Description<__wchar_t> ^ cDscr = gcnew Description<__wchar_t>; cDscr->Value = 'G'; cDscr->Message = L"Character"; cDscr->Show(); // Call the function and pass it a double-precision value // Declare the variable on the managed heap Description<double> ^ dDscr = gcnew Description<double>(355.65); dDscr->Message = L"Decimal"; dDscr->Show(); return 0; }
Based on this, the class keyword used for a template creation can be replaced with typename.
A Class Template With Multiple Parameters |
Using Multiple Templates Types |
When creating a template, you can specify more than one type. To do this, in the <> delimiters, after the first template type, enter a comma and declare an identifier that has a type and a name. Here is an example:
template <class TypeOfValue, __wchar_t c> public ref class Description { public: Description(); Description(TypeOfValue type) : Value(type) { } ~Description(); void Show(); String ^ Message; TypeOfValue Value; };
In this case, the second type must be, and will be treated as, a constant. When creating the body of a method outside of the class, make sure you specify the second type. Also, in the operators that follow the name of the class, enter the name of the second type. Here is an example:
template <class TypeOfValue, __wchar_t c> Description<TypeOfValue, c>::Description() { }
When implementing the method, use the second argument as you judge necessary. This should be easy because you know exactly its type. You can display its value or you can involve it in an operation of your choice. In the following example, the second type carries an indication of the message to be displayed. To identified that message, the value of the second argument is evaluated by a switch conditional statement:
template <class TypeOfValue, __wchar_t c> void Description<TypeOfValue, c>::Show() { switch(c) { case L'i': case L'I': Console::Write(L"Integer: "); break; case L'c': case L'C': Console::Write(L"Character: "); break; case L'f': case L'F': case L'd': case L'D': Console::Write(L"Decimal: "); break; } Console::WriteLine(L"{0}", Value); }
When instantiating the class, you must specify the second type also. To do this, after the first type and its comma in the < and > operators, enter a constant value for the second type. Here are examples:
int main() { // Call the function and pass it an integer value // Declare the variable on the stack heap Description<int, L'i'> iDscr; iDscr.Value = 246; iDscr.Message = L'i'; iDscr.Show(); // Call the function and pass it a character value // Declare the variable on the managed heap Description<__wchar_t, L'c'> ^ cDscr = gcnew Description<__wchar_t, L'c'>; cDscr->Value = 'G'; cDscr->Message = L'c'; cDscr->Show(); // Call the function and pass it a double-precision value // Declare the variable on the managed heap Description<double, L'f'> ^ dDscr = gcnew Description<double, L'f'>(355.65, L'f'); dDscr->Message = L'f'; dDscr->Show(); return 0; }
A Constant Template Parameter |
Once again, remember that the second parameter is treated as a constant; therefore, it can be declared using the const keyword. Here is an example:
using namespace System; template <class TypeOfValue, const __wchar_t c> public ref class Description { public: Description(); Description(TypeOfValue type, const __wchar_t msg) : Value(type), Message(msg) { } ~Description(); void Show(); __wchar_t Message; TypeOfValue Value; }; template <class TypeOfValue, const __wchar_t c> Description<TypeOfValue, c>::Description() { } template <class TypeOfValue, const __wchar_t c> Description<TypeOfValue, c>::~Description() { Message = L'i'; } template <class TypeOfValue, const __wchar_t c> void Description<TypeOfValue, c>::Show() { switch(c) { case L'i': case L'I': Console::Write(L"Integer: "); break; case L'c': case L'C': Console::Write(L"Character: "); break; case L'f': case L'F': case L'd': case L'D': Console::Write(L"Decimal: "); break; } Console::WriteLine(L"{0}", Value); }
A Default Value for a Template Parameter |
The second parameter of a class template can be assigned a default value. Based on the rules of a default value, this value would be used for the parameter if you don't supply a value for it. The default value can be assigned only in the declaration preceding the class creation. Here is an example:
using namespace System; template <class TypeOfValue, const __wchar_t c = L'i'> public ref class Description { public: Description(); Description(TypeOfValue type, const __wchar_t msg) : Value(type), Message(msg) { } ~Description(); void Show(); __wchar_t Message; TypeOfValue Value; }; template <class TypeOfValue, const __wchar_t c> Description<TypeOfValue, c>::Description() { } template <class TypeOfValue, const __wchar_t c> Description<TypeOfValue, c>::~Description() { } template <class TypeOfValue, const __wchar_t c> void Description<TypeOfValue, c>::Show() { switch(c) { case L'i': case L'I': Console::Write(L"Integer: "); break; case L'c': case L'C': Console::Write(L"Character: "); break; case L'f': case L'F': case L'd': case L'D': Console::Write(L"Decimal: "); break; } Console::WriteLine(L"{0}", Value); }
When declaring a variable for the class, you can omit the second parameter if you want. In this case, the default value would be used. Here are two examples:
int main() { // Call the function and pass it an integer value Description<int, L'i'> iDscr; iDscr.Value = 246; iDscr.Message = L'i'; iDscr.Show(); // Notice that the second argument is not specified // This means that the default value will be used Description<__wchar_t> ^ cDscr = gcnew Description<__wchar_t>; cDscr->Value = 'G'; cDscr->Message = L'c'; cDscr->Show(); // Once again, notice that the second argument is not specified // The default value will be used for the parameter Description<double> ^ dDscr = gcnew Description<double>(355.65, L'f'); dDscr->Message = L'f'; dDscr->Show(); return 0; }
This would produce:
Integer: 246 Integer: G Integer: 355.65 Press any key to continue . . .
If you predict that the value of the first parameter can be assigned to the second one, you can use that first parameter's value and assign it to the second to be its default value.
A Class Template as a Template Parameter |
When creating a class template, the first parameter can itself be a class template. To create such a class, inside the <> expression, include the type of declaration we have been using so far preceding a class creation. This expression itself becomes template parameter and can be used to precede the class keyword that is used to create a class template. Here is an example of such a class:
template <template <class SomeType> class ValueType> public ref class Homework { };
Of course, a class must have been previously created so it can be used as a parameter. Here is an example:
template <class TypeOfValue> public ref class Description { }; template <template <class SomeType> class ValueType> public ref class Homework { };
Notice that both classes have nothing in common and they are not sharing any information.
|
|||
Previous | Copyright © 2006-2025, FunctionX | Saturday 29 April 2023, 22:44 | Next |
|