Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

The New C++: Typedef Templates


December 2002 C++ Experts Forum/The New C++


Two columns ago [1], I promised to give more details about typedef templates, which is a likely proposal for inclusion in the next C++ Standard, C++0x. This month, I'm coming through on that promise. In this article, I'll present an overview of the proposed typedef templates. The rest of this article is based directly on the typedef template proposal paper I wrote for the October 2002 C++ Standards meeting [2].

In short, why should we care about typedef templates? Because they make C++ libraries somewhat easier to create and to use, for reasons in the references above and others shown herein. Also, frankly, the absence of typedef templates is essentially just an oversight in the first C++ Standard. Now let's jump into some details.

1. The Problem and Current Workarounds

We would like to allow the programmer to create a synonym for a template where some, but not all, actual template arguments are fixed. The problem is important because such a facility would make it possible to create more easily usable template libraries. For example, consider a template like this:

template<typename T1,
         typename T2,
         typename T3 = int
         typename T4 = string>
class C { /*...*/ };

Today, default template arguments already enable programmers to use the template more naturally (and less tediously) as just:

C<bool, short> x; // synonym for C<bool, short, int, string>

Alternatively, we can also use typedefs to create a synonym for another type, including a synonym for a template specialization with all actual template arguments specified:

typedef C<bool, short, long, wstring> Phil;
Phil p;

It is not, however, possible in general to use default arguments or typedefs to create a more usable name for a template where some, but not all, actual template arguments are fixed. The ability to create a synonym that specified only some template arguments while allowing others to still vary would be useful and help to create more naturally usable names in libraries.

In existing practice, including in the standard library, type names nested inside helper templates are used to work around this problem. The following is one example of this workaround; one thing we would like to do is avoid the "::Type."

template< typename T >
struct SharedPtr
{
 typedef Loki::SmartPtr
    <
      T,                // note, T still varies
      RefCounted,       // but everything else is fixed
      NoChecking,
      false,
      PointsToOneObject,
      SingleThreaded,
      SimplePointer<T> // note, T can be used as here
    >
    Type;
};

SharedPtr<int>::Type p; // sample usage, "::Type" is ugly

For another example, the standard library's rebind helpers fall into this category:

template<typename T> class allocator { //...
 template<typename U>
 struct rebind { typedef allocator<U> other; };
};

// usage: allocator<T>::rebind<U>::other

What we'd really like to be able to do is simply this:

template<typename T> class allocator { //...
 template<typename U>
 typedef allocator<U> rebind;
};
<br>
// usage: allocator<T>::rebind<U>

In fact, the Standard itself says: "The template class member rebind [...] is effectively a template typedef: if the name Allocator is bound to SomeAllocator<T>, then Allocator::rebind<U>::other is the same type as SomeAllocator<U>." [Emphasis mine.]

These workarounds are ugly, and besides they do not work for all cases. (For one thing, the workaround can't match a template template parameter.)

This proposal fits into the categories of:

  • Improve support for library building.
  • Improve support for generic programming.
  • Remove embarrassments (inasmuch as the absence of typedef templates is a known weakness in the language).

2. The Proposal

2.1 Basic Cases

A typedef introduces a synonym, rather than a complete new type. Similarly, a typedef template introduces a parameterized synonym, not a complete new type. One purpose for allowing templatization of a typedef is to introduce a simplified synonym for an existing template where some but not all template arguments are fixed. For example:

template<typename A, typename B> class X { /* ... */ };
<b>template<typename T> typedef </b>X<T,int> Xi;
Xi<double> Ddi; // equivalent to X<double,int>

A typedef template can be modeled like a partial specialization, with the definition being the primary class template. The syntax naturally follows the existing syntax for function and class templates:

void f( int ); // function
template<typename T> void f( T );
               // function template, usage f<int>

class X { };   // class
template<typename T> class X { };
               // class template, usage X<int>

typedef map<string, Employee> EmployeeRegistry; 
               // typedef
<b>template<typename T></b> typedef map<string, <b>T</b>> Registry;
               // typedef template, 
               // usage Registry<Employee>

It uses the same rules as function and class templates for dependent names (including the use of typename within the typedef template for dependent type names), non-type parameters, and template template parameters.

Here's an example that comes up in many class templates, particularly in policy-based design (heavily used in Loki) where there are many template parameters and we currently can't express a typedef name that fixes some but not all of the types. In this example, I cite Loki's SmartPtr, which is very flexible because it allows customization via several policy template parameters. Unfortunately, having so many template parameters also makes it harder to use. There are several common uses of Loki's SmartPtr with particular template parameters fixed that it would be useful to be able to invoke more simply via a synonym. For example:

<b>template< typename T >
typedef Loki::SmartPtr</b>
    <
      <b>T,                // note, T still varies</b>
      RefCounted,       // but everything else is fixed
      NoChecking,
      false,
      PointsToOneObject,
      SingleThreaded,
      SimplePointer<<b>T</b>> // note, T can be used as here
    >
    <b>SharedPtr;</b>

<b>template< typename T >
typedef</b> Loki::SmartPtr
    <
      <b>T,</b>
      RefCounted,
      NoChecking,
      false,
      PointsToArray,
      SingleThreaded,
      SimplePointer<<b>T</b>> 
    >
    <b>SharedArray;</b>

<b>template< typename T >
typedef Loki::SmartPtr</b>
    <
      <b>T,</b>
      NonCopyable, 
      NoChecking,
      false,
      PointsToOneObject,
      SingleThreaded,
      SimplePointer<<b>T</b>> 
    >
    <b>ScopedPtr;</b>

<b>template< typename T >
typedef</b> Loki::SmartPtr
    <
      <b>T,</b>
      NonCopyable,
      NoChecking,
      false,
      PointsToArray,
      SingleThreaded,
      SimplePointer<<b>T</b>> 
    >
    <b>ScopedArray;</b>

2.2 Advanced Cases: Specialization

Consider the following typedef template:

template<typename A, typename B> class X { /* ... */ };
<b>template<typename T> typedef </b>X<T,int> Xi;

To specialize the typedef template, use the same syntax as when specializing class and function templates:

// specialization for string
<b>template<> typedef </b>UnrelatedType Xi<b><string></b>;

...

Xi<double> Ddi;  // uses base template
Xi<string> Ssi;  // uses specialization

To partially specialize the typedef template, use the same syntax as when partially specializing class and function templates — the only trick is to remember where the template argument list goes, namely right after the name being specialized. For class templates, the Standard says: "For partial specializations, the template argument list is explicitly written immediately following the class template name." So, for partial specializations of typedef templates, the template argument list is explicitly written immediately following the typedef template name:

// partial specialization for pointers
<b>template<typename T> typedef </b>AnotherUnrelatedType<T> Xi<b><T*></b>;

...

Xi<double> Ddi; // uses base template
Xi<int*> Ipi; // uses partial specialization

3. Interactions and Implementability

The proposed feature is intended to be a natural application of existing template syntax to the existing typedef keyword. Interactions with the rest of the language are limited because typedef templates do not create a new type or extend the type system in any way; they only create synonyms for other types.

This is not a one-off or special-purpose feature. Consider the example in 2.2, and the ease of use of letting the programmer write:

SharedPtr<int> p;
SharedArray<int> a;

instead of:

SharedPtr<int>::Type p;
SharedArray<int>::Type a;

or, worse still:

SmartPtr<int, RefCounted, NoChecking, false,
         PointsToOneObject, SingleThreaded,
         SimplePointer<int> > p;

SmartPtr<int, RefCounted, NoChecking, false,
         PointsToArray, SingleThreaded,
         SimplePointer<int> > a;

The naturalness and ease of use of the first case is possible only with typedef templates and will make advanced C++ libraries more accessible to programmers.

A typedef template can be used as a template template argument if it otherwise matches the rules for such an argument. When so used, however, it is just a "syntactic sugar" synonym. Because typedef templates can be specialized, at the point of instantiation the typedef template specialization (if any) is found and used, and if it refers to another template then that template's specialization (if any) is also found and used.

It is recommended that a typedef template parameter be deducible as in this example:

template<typename T>
typedef T MyT;

template<typename T>
void f( MyT<T> );

void g() {
  MyT<int> val = 42;
  f( val );   // succeeds, T is deduced to be int
  f( 42 );    // fails, T can't be deduced
}

Summary

typedef templates are absent by oversight from Standard C++. They promise to make C++ libraries somewhat easier to create and to use, for reasons in the references below and the examples shown in this article.

For more information, see also the following related material that I've written. You may find it useful as background or to pursue particular topics:

  • For more on the usefulness of typedef as it currently exists, especially in template and STL-aware code, see [3].
  • For ideas on how to work around the absence of typedef templates, see [4].

As I write this, I'm about to head down to Santa Cruz for the fall C and C++ standards meetings. So stay tuned: next time, I'll cover news from the October 2002 meeting.

Acknowledgments

Thanks to Jason Shirk (who wrote the sample typedef template implementation in an internal build of the Microsoft compiler) and Jeff Peil for detailed comments, as well as to Jason, Bjarne Stroustrup, and Andrei Alexandrescu for a fun lunch at the April 2002 ACCU conference where we played with the sample implementation. For the record, the first time Andrei laid eyes on the typedef template feature, his eyes lit up with glee, he sat down at the computer, started to type — and the very first thing he tried to do was partially specialize it. That's Andrei!

References

[1] H. Sutter. "The New C++: Smart(er) Pointers," C/C++ Users Journal C++ Experts Forum, August 2002, <www.cuj.com/experts/2008/sutter.htm>.

[2] H. Sutter. "Proposed Addition to C+: Typedef Templates", ISO/ANSI C++ standards committee paper (ISO/IEC JTC1/SC22/WG21 paper N1373, ANSI/NCITS J16 paper 02-0031).

[3] H. Sutter. "Typedefs," Guru of the Week #46, available online at <www.gotw.ca/gotw/046.htm>.

[4] H. Sutter. "Template Typedef," Guru of the Week #79, available online at <www.gotw.ca/gotw/079.htm>.

Herb Sutter (<www.gotw.ca>) is convener of the ISO C++ standards committee, author of the acclaimed books Exceptional C++ and More Exceptional C++, and one of the instructors of The C++ Seminar (<www.gotw.ca/cpp_seminar>). In addition to his independent writing and consulting, he is also C++ community liaison for Microsoft.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.