Home

Generic Functions

 

Introduction

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.

Generic Creation

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;
}
 

Previous Copyright © 2006 FunctionX, Inc. Next