[Please do not mail me a copy of your followup]
Paul <
peps...@gmail.com> spake the secret code
<
d1eb8ca9-f225-4ca4...@googlegroups.com> thusly:
Sure, let's go back and look at your code, reformatted slightly:
template <typename RandomAccessIterator>
// 1st use of typename keyword
void quicksort(RandomAccessIterator begin, RandomAccessIterator end)
{
if (begin != end)
{
typdef
typename std::iterator_traits<RandomAccessIterator>::value_type
// 2nd use of typename keyword
iterator_value_type;
RandomAccessIterator pivot = std::partition(begin, end,
bind2nd(std::less<iterator_value_type>(), *begin));
quicksort( begin, pivot);
RandomAccessIterator new_pivot = begin;
quicksort(++new_pivot, end);
}
}
(Here, I've introduced a local typedef for the value type of the random
access iterator that we got from std::iterator_traits.)
When you write a template function, you have to tell the template
mechanism what kind of template arguments are supplied to your template
function. It was always allowed that you could write 'typename' or
'class' to indicate that the argument was expected to be a type and not
an integral constant. 'class' seemed to be more commonly used in the
past and over time the community has shifted to favoring the 'typename'
because it is more intention-revealing than 'class'. (The supplied
type need not be a class, it could be a builtin type like int, or it
could be a struct or union.) This is how typename is used in the
first location in your code.
In the second location, we're instantiating a template with a type
argument. That type argument comes from a nested name inside another
template, in this case the other template is std::iterator_traits and
the nested name is value_type. Here we need to use typename to tell
the compiler that the nested name refers to a type and not a function
or data member. (Note that the nested name needn't be a name
introduced by a typedef but it often is. It could be a nested class
or struct or union as well.)