This is going to be rather long, so I apologize preemptively.
Near the end of Item 47 in Scott Meyers's "Effective C++" (Third Edition) he shows the following code:
template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d)
{
doAdvance( iter, d,
typename std::iterator_traits<IterT>::iterator_category() );
}
He's already defined a number of overloaded doAdvance functions that take as their third argument std::random_access_iterator_tag, std::bidirectional_iterator_tag, or std::input_iterator_tag.
So here's my question: why is he appending () to std::iterator_traits::iterator_category? Initially I thought this was a typo (since it's not discussed at all in the main text) but then I saw that in Section 7.5.1 of Nicolai Josuttis's "The C++ Standard Library: A Tutorial and Reference" he has an example that for my purposes is equivalent:
template <class Iterator>
inline void foo (Iterator beg, Iterator end)
{
foo ( beg, end,
std::iterator_traits<Iterator>::iterator_category() );
}
OK, so it seems it's not a typo. When I see () next to a type name I think value-initialization. But I don't see why you would want to do that in this context. std::iterator_traits::iterator_category is simply a typedef for an iterator tag, and both Meyers and Josuttis show these to have the following hierarchy:
namespace std {
struct output_iterator_tag {
};
struct input_iterator_tag {
};
struct forward_iterator_tag
: public input_iterator_tag {
};
struct bidirectional_iterator_tag
: public forward_iterator_tag {
};
struct random_access_iterator_tag
: public bidirectional_iterator_tag {
};
}
I then thought that maybe they're not showing the actual contents of the different iterator tags for brevity, so I looked at GCC's stl_iterator_base_types.h on my system and it looks identical. In other words, the only things in there are what the compiler will put in there.
I'm reaching the conclusion that it doesn't matter if you write std::iterator_traits::iterator_category or std::iterator_traits::iterator_category(), but since I'm not 100% sure I thought I'd ask the stackoverflow crowd. Thanks!
EDIT: I want to thank James for his answer which has (albeit indirectly) helped me realize what the source of my confusion was. The first of the doAdvance function templates looks like this:
template<typename IterT, typename DistT>
void doAdvance(IterT& iter, DistT d,
std::random_access_iterator_tag)
{
iter += d;
}
The third parameter is a type unaccompanied by a variable name, i.e. it is an unnamed parameter. I had never seen an unnamed parameter in a function definition before; I think this is why I got confused. In this case having an unnamed parameter isn't a problem, since that argument is only used during the resolution of which overloaded function to use. Even so, when you call a function you need to pass an object, not a type.
Thus, it turns out that the value-initialization that Meyers and Josuttis used was necessary: they need to pass an object (even a temporary unnamed one), not a type.