1

From Scott Meyers's book, names in a template that are dependent on a template parameter are called dependent names. (When a dependent name is nested inside a class, I call it a nested dependent name)

So its necessary to use "typename" keyword before the dependent name, right?

template<typename C>
void print2nd(const C& container) {
typename C::const_iterator iter(container.begin()); 
...
}

But why in this code, taken from Josuttis book, std::vector that is another template's instantiation which is obviously dependent on T, they do not use "typename" here:

template <typename T>
class Stack {
    (?typename?) std::vector<T> elems;
...
};

It all looks confusing especially with another example from Meyers:

template<typename IterT> 
void workWithIterator(IterT iter) {
    typename std::iterator_traits<IterT>::value_type temp(*iter);
... }

They look all the same to me. How do you differentiate?

barney
  • 2,172
  • 1
  • 16
  • 25

2 Answers2

2

In the first example (typename C::const_iterator), const_iterator cannot be known to the compiler firsthand: it could be a static member, for instance. This is why you need to prefix the declaration with typename, to indicate it is a type.

In the second example, the compiler knows std::vector<T> is a type, even without knowing what is T. Which is why typename is not needed in this case.

piwi
  • 5,136
  • 2
  • 24
  • 48
  • How exactly do you know, that C::const_iterator cannot be known? Is it because its nested to unknown type C ? Then, here's another example from Meyers: template void workWithIterator(IterT iter) { typename std::iterator_traits::value_type temp(*iter); ... } – barney Apr 12 '17 at 14:13
  • @barney Yes, it is because it is nested in `C`, so the compiler has a hard time deciding at this point what is `const_iterator`. As mentioned, you could have a `static int const_iterator` nested in `C`, which is a static member named `const_iterator` of type `int`, not a type. But prefixing with `typename` in this case means "`const_iterator` is a type name". However, `std::vector<>` is a type (which takes a template parameter), and the compiler knows that, so the compiler figures that without knowing the exact type of `C`. – piwi Apr 12 '17 at 14:21
  • 1
    @barney For the other example you mention (`std::iterator_traits::value_type`): `iterator_traits` is known as a type, but the compiler does not know what is within the specific `iterator_traits` implementation (because the class could be specialized for the type behind `IterT`), so you need to use `typename` to indicate you refer to a type, just like the `C::const_iterator` example. – piwi Apr 12 '17 at 20:27
1

When you have

typename C::const_iterator iter(container.begin()); 

The const_iterator part is a type that depends on what C is. So you need typename there to tell the compiler that C::const_iterator is a type.

In

std::vector<T> elems;

You are declaring a std::vector whose elements are of type T. You do not need typename there at all. Even though vector depends on the type T it is not a name dependent on what T is.

You can read more about when and where typename and template are required at Where and why do I have to put the "template" and "typename" keywords?

Community
  • 1
  • 1
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • 1
    I'm struggling to get the difference :) So, when compiler sees "C::const_iterator" its unknown before instantiation/ substitution of C for any concrete type, what the "const_iterator" is, right? But the "std::vector" also depends on the exact concrete T, or its not? Just because IT IS the instantiation? – barney Apr 12 '17 at 14:16
  • Another example from Meyers refers to something similar to vector but with "typename" keyword still: template void workWithIterator(IterT iter) { typename std::iterator_traits::value_type temp(*iter); ... } why here ? what is the difference of iterator_traits with vector ? – barney Apr 12 '17 at 14:19
  • @barney When the compiler sees `some_name::some_other_name` it does not expect to see a type when `some_name` is a template type. So you use `typename` to tell it is a name and not a non-name like it assumes. – NathanOliver Apr 12 '17 at 14:19