The templates we studied in the previous lesson are part of
the C++ programming language. To update their usefulness and adapt them to the
.NET Framework, Microsoft added the concept of generic to the C++/CLI language.
Like a template, a generic is a type of value used by a function without the
function knowing what data type the value is made for. While templates in their
format are not formally used by other languages of the .NET Framework such as C#
or Visual Basic, generics are.
In the previous lesson, we saw that you might have a
function used to display different types of values:
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
Console::Write(L"Value: ");
Show(246);
// Call the version of the function that displays a character
Console::Write(L"Value: ");
Show('G');
// Call the version of the function that displays a decimal
Console::Write(L"Value: ");
Show(355.65);
return 0;
}
We then saw that you could create a template function with a
parameter whose type was not known in advance:
template <class TypeOfValue>
void Show(TypeOfValue value)
{
Console::WriteLine(value);
}
After creating the function, you could call it by specifying
the type of value it would process:
using namespace System;
template <class TypeOfValue>
void Show(TypeOfValue value)
{
Console::WriteLine(value);
}
int main()
{
// Call the version of the function that displays an integer
int Integer = 246;
Console::Write(L"Value: ");
Show<int>(Integer);
// Call the version of the function that displays a character
__wchar_t Character = L'G';
Console::Write(L"Value: ");
Show<__wchar_t>(Character);
// Call the version of the function that displays a decimal
double DoublePrecision = 355.65;
Console::Write(L"Value: ");
Show<double>(DoublePrecision);
return 0;
}
To create a generic, instead of template, you use the
generic keyword following the format we reviewed for the template in the
previous lesson. Here is an example:
using namespace System;
generic <class TypeOfValue>
void Show(TypeOfValue value)
{
Console::WriteLine(value);
}
int main()
{
// Call the version of the function that displays an integer
int Integer = 246;
Console::Write(L"Value: ");
Show<int>(Integer);
// Call the version of the function that displays a character
__wchar_t Character = L'G';
Console::Write(L"Value: ");
Show<__wchar_t>(Character);
// Call the version of the function that displays a decimal
double DoublePrecision = 355.65;
Console::Write(L"Value: ");
Show<double>(DoublePrecision);
return 0;
}
This would produce:
Value: 246
Value: G
Value: 355.65
Press any key to continue . . .
When creating a template, we saw that you could replace the class
keyword with typename. This is also valid for a generic. Here is an
example:
generic <typename TypeOfValue>
void Show(TypeOfValue value)
{
Console::WriteLine(value);
}
Differences Between Templates and Generics |
|
As mentioned earlier, templates are part of the C++ language
but generics are mainly a concept of the .NET Framework. Some concepts of templates, as they relate to C++, are not present in the CLR
because other languages of the CLI don't use them. For example, we saw that a
template parameter could be passed as a reference. Consider the following
function:
template <class TypeOfValue>
void Show(TypeOfValue &value)
{
Console::WriteLine(value);
}
This would compile fine. Imagine you make this a generic:
generic <class TypeOfValue>
void Show(TypeOfValue &value)
{
Console::WriteLine(value);
}
In Microsoft Visual C++ 2005, you would receive a C3229 error:
error C3229: 'TypeOfValue &' : indirections on a generic type parameter
are not allowed compiler using 'TypeOfValue' to continue parsing
We also saw that a template parameter could be passed as a
pointer. Since pointers are not directly supported by other CLI languages like
Visual Basic, a parameter cannot be passed as a pointer. Therefore, the
following will not work:
generic <class TypeOfValue>
void Show(TypeOfValue *value)
{
Console::WriteLine(*value);
}
Like a template, the parameter type of a generic can be
regular value of a primitive type. Unlike a template, if the parameter type of a
generic is a primitive type, it cannot be passed as a handle. For this reason, the
following would not compile:
using namespace System;
generic <class TypeOfValue>
void Show(TypeOfValue ^ value)
{
Console::WriteLine(value);
}
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;
}
In Microsoft Visual C++ 2005, the program would produce the
following errors:
error C3229: 'TypeOfValue ^' : indirections on a generic type parameter
are not allowed compiler using 'TypeOfValue' to continue parsing
error C2664: 'Show' : cannot convert parameter 1 from 'System::Int32 ^' to 'int'
No user-defined-conversion operator available, or
There is no context in which this conversion is possible
error C2664: 'Show' : cannot convert parameter 1 from 'System::Char ^' to 'wchar_t'
No user-defined-conversion operator available, or
There is no context in which this conversion is possible
error C2664: 'Show' : cannot convert parameter 1 from 'System::Double ^' to 'double'
No user-defined-conversion operator available, or
There is no context in which this conversion is possible
But, you can declare a handle and pass it as the value of a
pointer when calling the generic function. Here are examples:
using namespace System;
generic <class TypeOfValue>
void Show(TypeOfValue value)
{
Console::WriteLine(value);
}
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;
}
|