CS 70

Example: IntVector to Vector<T>

Here's a bigger example, where we've converted our IntVector class into a Vector<T> class template.

Open both at once (ideally, try to have them side by side in separate windows) and compare the code to see how it has changed.

What's one thing you observe from looking at what's changed? (e.g., from looking at vector-private.hpp)

  • Goat speaking

    Gah! That was a lot of template <typename T> repeated everywhere. I thought we were trying to avoid copying and pasting code!

  • Bjarne speaking

  • Horse speaking

    Hay! There was something else I didn't expect. What was the deal with

    typename Vector<T>::iterator  ?
    

    I expected just

    Vector<T>::iterator  .
    
  • LHS Cow speaking

    Oh, well spotted! You've noticed something pretty subtle that we have to get used to.

  • Goat speaking

    Come on, Bjarne, tell us it's part of C++'s heritage.

  • Bjarne speaking

    No, this doesn't come from our C history. This is… all original to C++.

  • LHS Cow speaking

    Okay, folks, there are two ways to look at things…

When to Add typename—The Practical View

One way to look at this code is to say, “This is simply some bizarre C++ nonsense, and you just have to sometimes scatter the word typename into your code”. The good news is, if you don't say typename where you need to say it, the compiler will give you a pretty clear error to tell you how to fix the issue.

These errors look like

./vector-private.hpp:114:1: error: missing 'typename' prior to dependent type name 'Vector<T>::iterator'
Vector<T>::iterator Vector<T>::end() {
^~~~~~~~~~~~~~~~~~~
typename
1 error generated.

The compiler is pretty clearly saying “put typename here”. Do as it says, and all will be well.

When to Add typename—The Why

Suppose we have a template type parameter T. Do you think the following are types or values?

  1. T::const_iterator
  2. T::max_size
  3. T::snoozlewuzzle

You probably think the first one is a type (for an iterator), and the second one is a value (probably a size_t value). But what about the third one?

  • Alien speaking

    I know what a “snoozlewuzzle” is, but I can't reveal that knowledge to you.

Knowing nothing at all about what T is, what do you know about T::snoozlewuzzle?

We don't know what T::snoozlewuzzle is. Also, we don't even know for sure what T::const_iterator is. Some joker could have defined a class that has a member variable named const_iterator, and, because we don't know what T is, we can't be sure that T isn't such a class, even though it would be pretty weird to have done that.

So, for all these cases, the compiler can't be sure what it's dealing with. So it adopts a very simple rule: if it doesn't know what something is for sure, always assume that something is not a type.

When the thing is a type, we have to put typename in front of it to clue the compiler in. But we only need to do it when there is a template type argument involved.

  • Duck speaking

    But it wasn't just T::iterator, it was Vector<T>::iterator. Why can't it look at the Vector class template and know?

  • Bjarne speaking

    It is still a dependent name and there is also template specialization to consider…

  • LHS Cow speaking

    Let's not get too far into the weeds here. The big picture is that if you have a template type parameter in there, you probably need typename.

  • Bjarne speaking

    Until C++20, when we've made the compiler smarter.

  • Goat speaking

    The compiler was already smarter. It has to give us good error messages about where we were supposed to put typename.

  • Bjarne speaking

    Yes. That's one reason we're relaxing the rules a bit.

  • LHS Cow speaking

    Unfortunately, C++20 support in current compilers is still a bit patchy, so we're sticking to C++17 in CS 70 for now.

  • RHS Cow speaking

    But some day, most of this nonsense will go away.

  • Dog speaking

    I'm excited for that day!

Overall Tips

The compiler is actually super helpful if you forget to put typename where you need it. It will tell you exactly where to put it. So don't worry too much about it.

On the other hand, if you get all overzealous and throw typename in places where it isn't needed, you'll totally confuse the poor compiler which will assume you're a clever C++ pro and doing weird things on purpose. It will then give you a very confusing error message that will be hard to figure out.

You'll probably want to have an example like this one nearby when you first start out making class templates so you check your code against the example.

(When logged in, completion status appears here.)