Partial Template Specialization with Visual C++ .NET 2003

From Kate Gregory's Codeguru column, "Using Visual C++ .NET".

-->

C++ templates are like a secret weapon for developers. Those who never got around to learning C++ because "it's really complicated" and "it has all kinds of funky features no one would ever use" have no idea what we can do with templates. In my previous column, I showed how the collection templates in the Standard Template Library can save you a lot of casting and runtime type conversions, while giving you rock-solid type safety that saves you from simple errors of thought. I even showed you how you can include pointers to managed objects in those types of collections, with the help of (what else?) a template.

Still, many programmers feel that templates are difficult, maybe even scary. And because of that, even many C++ programmers don't use them to the fullest. That's one of the reasons that Visual C++, until recently, didn't support the full glory of templates as laid out in the C++ Standard. Visual C++ .NET 2003, which released in April of this year, achieves an amazing 98% compliance with the standard, and that includes some dramatic template work.

Template Basics

You can use templates to define a global function, a class, or even a struct within your C++ application. I'm going to start with a simple global function called biggest. You could use this to determine which is the biggest of two integers, floating point numbers, or objects of your own design. Here's how to write the function:

template<class T>
T biggest(T a, T b)
{
   if (a > b)  return a;
   return b;
}

The <class T> syntax designates T in the lines that follow as a placeholder for whatever type the variables passed to biggest turn out to be. This function will work for any two items that are of the same type, and best of all, you don't have to use any weird punctuation to use it:

int x = biggest(3,4);
double d = biggest(4.1, -2.3);
SalesRep bestseller = biggest(John, Jane);
    // SalesRep instances created elsewhere,
    // operator> defined for SalesRep class

const char* Name = biggest("Hello","World");

That last one, however, tells a strange story. It seems that when you compare two character pointers with the > operator, you get whichever has the largest address in memory. That's almost certainly not what you wanted. And, because char* is a fundamental type, you can't overload the > operator yourself to get the desired behavior. Instead, you make a special version of the template that is just for char* comparisons:

template<>
const char* biggest(const char* a, const char* b)
{
   if (strcmp(a,b) > 0)  return a;
   return b;
}

Now you can compare literal char* strings correctly.

Partial Template Specialization

Some templates work with more than one class. This is especially likely when you're developing a library with collections, search and sort algorithms, and so on. For example, you might write a lookup table that holds objects and keys in pairs. Each instance of the collection would hold a particular type of object (Employee, SalesRep, Invoice, and so forth) with a particular type of key (integer, string, date, and the like)

I'm not going to code a lookup table class here—it's a lot of code—but you can imagine that you would have to write specialized implementations for some of the methods when the key is a char* string, because you can't just use the = operator to make a copy of a char* string. Yet, you don't want to write a specialized implementation for Employee and char*, SalesRep and char*, Invoice and char*, and so on. You want to write a partial template specialization, which works with any type of collected object when the key is a char*.

Until now, Visual C++ has not supported partial template specialization. It's something that you don't use day-to-day, so there hasn't been a lot of demand for it from customers. But over the last few years, some very powerful class libraries have been developed, such as Loki, Blitz, and Boost. Visual C++ couldn't even compile these libraries because they relied on these pushing-the-envelope features of the standard: partial template specialization, template template parameters, and the like. Now, starting with Visual C++ .NET 2003, these libraries will compile, which makes them available to you.

I'll show you a quick example just to prove that partial template specialization works. Here's a templated class called Pair that holds a pair of values:

template <class A, class B>
class Pair
{
private:
  A a;
  B b;
public:
  Pair(A aa, B bb):a(aa),b(bb) {}
  void display()
  {
    cout << a << ' ' << b << endl;
  }
};

To use this class, you declare the template parameters explicitly when you declare an instance of the class:

Pair<double,double> doubledouble(1.2,2.3);
doubledouble.display();

Now, here's a partial template specialization of the Pair class. It has special code when the second parameter is an int. I'm not going to pretend this special code makes any sense (why would you square the second parameter only if it was an integer?), but it's easy to tell that it's executing, and it proves the concept.

template <class A>
class Pair<A, int>
{
private:
  A a;
  int b;
public:
  Pair(A aa, int bb):a(aa),b(bb*bb) {}
  void display()
  {
    cout << a << ' ' << b << endl;
  }
};

Using the partially-specialized template is no different from using the original template:

Pair<double,int> doubleint(2.2,3);
doubleint.display();

When this code runs, it prints out "2.2 9" because the integer is squared. This demonstrates that the partial specialization is in fact being used.

You can compile and run this code in Visual Studio .NET 2003—but it won't compile in Visual C++ .NET 2002. This is just one example of the dramatically improved compliance to the C++ standard in the latest version of the compiler. Even if you'll never write a partial template specialization yourself, the support for it in the compiler opens a number of powerful class libraries to you—and that makes this something worth getting excited about.

About the Author

Kate Gregory is a founding partner of Gregory Consulting Limited (www.gregcons.com). In January 2002, she was appointed MSDN Regional Director for Toronto, Canada. Her experience with C++ stretches back to before Visual C++ existed. She is a well-known speaker and lecturer at colleges and Microsoft events on subjects such as .NET, Visual Studio, XML, UML, C++, Java, and the Internet. Kate and her colleagues at Gregory Consulting specialize in combining software develoment with Web site development to create active sites. They build quality custom and off-the-shelf software components for Web pages and other applications. Kate is the author of numerous books for Que, including Special Edition Using Visual C++ .NET.




Comments

  • partial template specialization for methods

    Posted by onkelhotte on 04/14/2005 10:06am

    If I have the following class: template class XYZ { void DoIt(int i); }; I want to implement two versions for DoIt: one for B = 0 and one for B = 1. I tried the following: template void XYZ::DoIt(int i) { // Do something } template void XYZ::DoIt(int i) { // Do something other } Under VC6 this doesn't work... Is this because of VC6 or is it generally wrong and how to make it ??? Thx!

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

  • Protecting business operations means shifting the priorities around availability from disaster recovery to business continuity. Enterprises are shifting their focus from recovery from a disaster to preventing the disaster in the first place. With this change in mindset, disaster recovery is no longer the first line of defense; the organizations with a smarter business continuity practice are less impacted when disasters strike. This SmartSelect will provide insight to help guide your enterprise toward better …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds