Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ Timesaving Techniques (2005) [eng].pdf
Скачиваний:
65
Добавлен:
16.08.2013
Размер:
8.35 Mб
Скачать

32 Creating Templates

from Functions and

Technique Methods

Save Time By

Creating function templates

Creating method templates

Interpreting your output

Although creating entire classes that are templates is useful, sometimes you just want a single function or method to accept a template argument. For example, if you created a comparison function

that used a template for all types, you could then create (say) a minimum function that would compare any two data types, including classes, as long as you could tell one was of lesser magnitude than the other. This technique shows how to save time by templatizing only a single function (and later, a single method) of a class.

Implementing Function Templates

A function template, or method template, is simply a standalone function (inside a class, in the case of a method) that can accept one or more template arguments. Let’s take a look at how you would implement function templates in your own code, by creating a generic function that will compute the minimum of two values.

1.

2.

In the code editor of your choice, create a new file to hold the code for the implementation of the source file.

In this example, the file is named ch32.cpp, although you can use whatever you choose.

Type the code from Listing 32-1 into your file.

Better yet, copy the code from the source file on this book’s companion Web site.

Implementing Function Templates

187

LISTING 32-1: THE MIN TEMPLATE FUNCTION

#include <stdio.h> #include <string>

template <class A>

A my_min( const A& val1, const A& val2)

{

if ( val1 == val2 ) return val1;

if ( val1 < val2 ) return val1;

return val2;

}

bool operator==(const std::string& s1, const std::string& s2)

{

int len = s1.length();

if ( len != s2.length() ) return false;

for ( int i=0; i<len; ++i ) if ( s1[i] != s2[i] )

return false;

return true;

}

bool operator <(const std::string& s1, const std::string& s2

{

int len = s1.length(); if ( len > s2.length() )

len = s2.length();

for ( int i=0; i<len; ++i ) if ( s1[i] > s2[i] )

return false;

return true;

}

int main(int argc, char **argv)

{

//First, try it for integers int x1 = 100;

int x2 = 30;

int xmin = my_min(x1, x2);

//Now, for floating-point numbers float f1 = 12.40;

float f2 = 4.90;

float fmin = my_min(f1, f2);

1

5

6

2

(continued)

188 Technique 32: Creating Templates from Functions and Methods

LISTING 32-1 (continued)

int xmin2 = my_min(x2, x1);

printf(“Xmin = %d\n”, xmin); printf(“Xmin2 = %d\n”, xmin2 ); printf(“Fmin = %f\n”, fmin );

//Now that we have implemented the operators,

//try it for strings.

std::string s1 = “Hello world”; std::string s2 = “Goodbye cruel world”;

if ( s1 == s2 )

printf(“Strings are equal\n”); else

if ( s1 < s2 )

printf(“string %s is less\n”, s1.c_str() ); else

printf(“String %s is less\n”, s2.c_str() );

std::string smin = my_min( s1, s2 );

printf(“Min for strings returned: %s\n”, smin.c_str() );

}

3

4

3. Save the source file in your code editor and close the code editor.

Note that we have created a templated function called my_min, shown at 1 (it was not called min, because that would conflict with a Standard Template Library (STL) function of the same name), which can be used with any data type that supports the equal (=) and less-than (<) operators.

In this case, the source code also implements less-than and equal-to operations for the standard string class in the STL. After we have implemented these operators, we can then instantiate the template for the string class.

4. Compile the source code with the compiler of your choice on the operating system of your choice.

When the program is run, if you have done everything properly, you should see the following output in the shell window:

$ ./a.exe Xmin = 30 Xmin2 = 30

Fmin = 4.900000

String Goodbye cruel world is less

Min for strings returned: Goodbye cruel world

Let’s look at this carefully, and see what is going on. We are calling the minimum function, my_min, in three locations, shown at the lines marked with 2,

3, and 4. The first line computes the min fortwo integers, the second for two floating point numbers, and the third for two strings.

Although integers and floating point numbers have their own comparison operators (less than, greater than, and so forth) built into the language, strings do not. Therefore, we implement the comparison functions that will be called by my_min at the lines marked 5 and 6. After all of this is done, the compiler generates the proper versions of these functions and you see the minimum calculation output shown above.

Creating Method Templates 189

In this example, the template is automatically generated. Unlike a template class, function templates don’t require the programmer to specify the class or type that the template is being implemented for. This saves a lot of time; you don’t have to track down where the template was instantiated. The linker is also smart enough, with most modern C++ compilers, to link only in one copy of a given template. This means that if you have multiple calls to a specific templated function in your program, only one will be in the final executable. If your linker is not that smart, you have to force the implementation of a given template in your code.

Creating Method Templates

Similarly, you can also create methods of classes that are themselves templates, even though the class as a whole might not be. You might want to do this as a way to avoid writing a lot of the same code over and over, such as creating a set of assignment methods for different data types.

When you find yourself writing the same method over and over, but specifying a different data type (such as a set method or an assignment operator) for each one, immediately think about creating a template method for that operation. This can save you a lot of time.

The following steps show you how to create a method template:

1. In the code editor of your choice, reopen the source file for the code that you just created.

In this example, the file is named ch32.cpp, although you can use whatever you choose.

2. Add the code from Listing 32-2 into your file.

Or better yet, copy the code from the source file on this book’s companion Web site.

LISTING 32-2: A CLASS WITH A TEMPLATED METHOD

class Foo

{

private:

std::string _name; int _value;

public:

Foo(void)

{

_name = “Nothing”; _value = 0;

}

Foo(const char *strName, int iValue)

{

_name = strName; _value = iValue;

}

Foo( const Foo& aCopy )

{

_name = aCopy._name; _value = aCopy._value;

}

Foo operator=( const Foo& aCopy )

{

_name = aCopy._name; _value = aCopy._value; return *this;

}

//Templatized method to add values template < class A >

void Add( const A& aValue )

{

_value += aValue;

}

//Templatized method to multiply values template < class A >

void Multiply( const A& aValue )

 

7

{

 

_value = _value * aValue;

}

// Method to dump the values void Print()

{

printf(“Name: [%s]\n”, _name.c_str()

);

printf(“Value: %d\n”, _value );

}

};

(continued)

190 Technique 32: Creating Templates from Functions and Methods

LISTING 32-2 (continued)

int operator*( int iValue, std::string s )

{

//Convert string to an integer int iMult = atoi( s.c_str() );

//Do the multiplication

int iResult = iValue * iMult; // Return it

return iResult;

}

The above listing shows a class, Foo, which contains a templated method called Multiply (shown at 7). This method will allow you to multiply various types of data and assign the result to a member variable within the class. Notice also the operator* function that is defined even to multiply our value by a string.

3. Change the main function of the source file to be as shown in Listing 32-3:

LISTING 32-3: THE TEST DRIVER FOR THE TEMPLATED METHOD

int main(int argc, char **argv)

{

//First, try it for integers int x1 = 100;

int x2 = 30;

int xmin = my_min(x1, x2);

//Now, for floating point numbers float f1 = 12.40;

float f2 = 4.90;

float fmin = my_min(f1, f2);

int xmin2 = my_min(x2, x1);

printf(“Xmin = %d\n”, xmin); printf(“Xmin2 = %d\n”, xmin2 ); printf(“Fmin = %f\n”, fmin );

//Now that we have implemented the oper

//ators, try it for strings. std::string s1 = “Hello world”; std::string s2 = “Goodbye cruel world”;

if ( s1 == s2 )

printf(“Strings are equal\n”); else

if ( s1 < s2 )

printf(“string %s is less\n”, s1.c_str() );

else

printf(“String %s is less\n”, s2.c_str() );

std::string smin = my_min( s1, s2 ); printf(“Min for strings returned: %s\n”, smin.c_str() );

Foo f(“MyFoo”, 10); f.Add( 12.0 ); f.Print(); f.Multiply( -1 ); f.Print();

f.Multiply(std::string(“12”));

f.Print();

}

Note that as with template functions, the programmer does not in any way create an instance of the templated member function. The compiler will create instances as needed, by matching up the possible template arguments with the available templates. Naturally, this will only work if the template class definition is available, so once again, the template methods must be in-line defined methods. Because there is no “natural” way in which to multiply a string by an integer, we define a global operator which accepts an integer value and a string, and returns the converted string multiplied by the integer. After this operator is defined, we can then pass in a string to the templated method. (If the operator was not defined, you get a compile error when the template is expanded and the integer multiplication by the input argument is attempted.) There is a quite a bit going on here, obviously.

4. Compile the source code with the compiler of your choice on the operating system of your choice.

Creating Method Templates 191

When the program is run, if you have done everything properly, you should see the following output in the shell window:

$ ./a.exe Xmin = 30 Xmin2 = 30

Fmin = 4.900000

String Goodbye cruel world is less

Min for strings returned: Goodbye cruel

 

 

world

 

8

Name: [MyFoo]

 

Value: 22

 

Name: [MyFoo]

Value: -22

Name: [MyFoo]

Value: -264

The initial part of our output is from the first part of this technique and has not changed. The second part, beginning with the line marked 8, shows the result of our templated method. As you can see, we first assign the member variable value the value 10. We then add 12 to it, resulting in the output of 22. Now, we start using the Multiple method. First, we multiply by an integer value of –1, resulting in the output of –22. Then we multiply by a string value

of 12, which is converted to an integer using the operator* function we defined, which results in –264 — the value that is printed out.

Note that the string is evaluated to its integer value, 12, and the result multiplied by the current value of –22. This results in a total of –264, which is the value displayed on the console window.