Writing a Member Function Template

Problem

You have a single member function that needs to take a parameter that can be of any type, and you can't or don't want to be constrained to a particular type or category of types (by using a base class pointer parameter).

Solution

Use a member function template and declare a template parameter for the type of object the function parameter is supposed to have. See Example 8-13 for a short example.

Example 8-13. Using a member function template

class ObjectManager {
public:
 template
 T* gimmeAnObject( );

 template
 void gimmeAnObject(T*& p);
};

template
T* ObjectManager::gimmeAnObject( ) {
 return(new T);
}

template
void ObjectManager::gimmeAnObject(T*& p) {
 p = new T;
}

class X { /* ... */ };
class Y { /* ... */ };

int main( ) {
 ObjectManager om;

 X* p1 = om.gimmeAnObject( ); // You have to specify the template
 Y* p2 = om.gimmeAnObject( ); // parameter

 om.gimmeAnObject(p1); // Not here, though, since the compiler can
 om.gimmeAnObject(p2); // deduce T from the arguments
}

 

Discussion

When talking about function or class templates, the words parameter and argument have some ambiguity. There are two kinds of each: template and function. Template parameters are the parameters in the angle brackets, e.g., T in Example 8-13, and function parameters are parameters in the conventional sense.

Consider the ObjectManager class in Example 8-13. It is a simplistic version of the Factory pattern discussed in Recipe 8.2, so I have defined the member function gimmeAnObject as something that creates new objects that client code would use instead of calling new directly. I can do this by either returning a pointer to a new object or by modifying a pointer passed in by the client code. Let's take a look at each approach.

Declaration of a template member function requires that you provide the template keyword and the template parameters.

template
T* gimmeAnObject( );

template
void gimmeAnObject(T*& p);

Both of these member functions happen to use T as the template parameter, but they don't need to; they each represent the template parameter for that member function only, so the names are unrelated. You have to do the same thing for your template member function definition, i.e., use the template keyword and list all the template parameters. Here's what my definitions look like:

template
T* ObjectManager::gimmeAnObject( ) {
 return(new T);
}

template
void ObjectManager::gimmeAnObject(T*& p) {
 p = new T;
}

There are a couple of ways to call template member functions. First, you can invoke them with explicit use of the template parameter, like this:

X* p1 = om.gimmeAnObject( );

X is just some class name. Or, you can let the compiler deduce the arguments for the template parameters by passing in arguments of the type(s) of the template parameters. For example, you can invoke the second form of gimmeAnObject without passing in anything in angle brackets:

om.gimmeAnObject(p1);

This is because the compiler can deduce T by looking at p1 and recognizing that it's an X*. Template deduction only works for function templates (member or not) and only works when the template parameters are deduced from the function arguments.

Member function templates aren't the most popular feature in C++, but they come in handy from time to time, so it's good to know how to write one. I often see the need crop up when I want a member function to work for types that are not related by inheritance. For example, if I have a member function foo that I want to take a single argument that is always going to be a class that inherits from some base class, I don't need a template: I can just make the parameter type a base class pointer or reference. Then, any objects of subclasses of the parameter class will work just finesuch is the way of C++.

But you may want a function that operates on parameters that don't all inherit from the same base class(es). In this case, you can either write the same member function several timesonce for each typeor make it a template member function. Using templates also permits specialization, which is a way of providing implementations of templates for particular template arguments. But that's beyond the scope of a single recipe, so I won't discuss it further here, but it's a powerful technique, so if template programming appeals to you, I encourage you check it out.

See Also

Recipe 8.11

Building C++ Applications

Code Organization

Numbers

Strings and Text

Dates and Times

Managing Data with Containers

Algorithms

Classes

Exceptions and Safety

Streams and Files

Science and Mathematics

Multithreading

Internationalization

XML

Miscellaneous

Index



C++ Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2006
Pages: 241

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net