When should I use the keyword "typename" when using templates
I've been working lately on a small project, and I couldn't figure out something..
I've been given a .h file that was containing a class, using a typename template. Inside that class there was a private class.
template <typename T>
class Something
{
public:
Something();
~Something();
Node* Function1(int index);
int Index(const T& id);
private:
class Node()
{
public:
T id;
//Imagine the rest for the Node
};
};
The problem occured when I wanted to define the functions of the class "Something"
Here's how I was doing it (in a .inl file)
template<typename T>
Node* Something::Function1(int index) //Is the return type well written?
{
// returns the node at the specified index
}
template<typename T>
int Something::Index(const T& id) //Is the parameter type well specified?
{
// returns the index of the node with the specified id
}
So the bugging part was in the definitions part... Do I have to tell the compiler that the return type (in this case Node*) uses the typename template (like this: typename Node*
) ? And what about the parameter ? typename const Node&
?
So basically, when do I have to specify wether the function/parameter uses a template?
Thanks for your time.
For Function1
, you need to tell the compiler what Node is -- in this case, it's a nested type inside Something<T>
. Because it's dependent on T
(it's a dependent name), you need to tell the compiler it's a type, so you must write it as typename Something<T>::Node
. The issue is that there might be some T
for which Something<T>::Node
isn't actually a type (i.e. if you partially specialize Something<T>
).
For Index
, what you have is fine -- const T&
is just a reference to a const T
, and the compiler knows what T
is.
The simple rule: You need to use the typename
keyword every time you name a type using the Class::Type
syntax, if the Class
part depends on a template parameter. (The Class
part might be a template parameter, or it might be a typedef
in your class template, etc.)
Edit: There's also some confusion about nested class scoping rules. This is mostly independent of the typename
issue, so here's a non-template example.
class Outer {
public:
class Inner {
};
Inner* func(Inner* obj);
};
Outer::Inner* func(Inner* obj)
{
}
The full name of Inner
is Outer::Inner
. But you can also use the shorter name Inner
anywhere from the scope of class Outer
, including all of the declaration of func
. At the definition of func
, the return type is NOT in the scope of Outer
, so the full name is necessary. But after the (
, the function parameters ARE in the scope of Outer
, so the short name is okay.
Combining this with the template-ness of the original example, since the equivalent of Outer
is Something<T>
, you need the typename
keyword to say Something<T>::Node
.
template<typename T>
typename Something<T>::Node * Something::Function1(int index) //Is the return type well written?
{
// returns the node at the specified index
}
typename
and class
are equivalent in template type parameter list:
template <class T> class C;
is the same as
template <typename T> class C;
Where the typename
is required is when referring to dependent names:
template <typename T> struct A {
typedef typename T::some_type container;
};