The problem here is that you are referring to a nested dependent type name (i.e. BLink is nested inside RingBuffer which is dependent on a template parameter)
You need to help your compiler a little in this case by stating that RingBuffer<T>::BLink
is an actual type name. You do this by using the typename
keyword.
template <typename T>
typename RingBuffer<T>::BLink * RingBuffer<T>::NewLink(const T& t)
{
// ...
}
Explanation:
The compiler cannot know if RingBuffer<T>::BLink
is a type name or a static member until the template parameter T
is known. When the compiler parses your function template T
is not known and the rule to solve the ambiguity is to default to "this is not a type name".
Another short example (blatantly copied from Scott Meyers' Effective C++):
template<typename C>
void print2nd(const C& container)
{
C::const_iterator * x;
…
}
This maybe illustrates the problem a little better as it's more compact. As already said it's not clear for the parser whether C::const_iterator is a type name or a static data member as it doesn't know what C
is when it parses this part of the code (it may know at a later point in time when the template is actually instantiated). So to ease the compiler implementers' lives this ambiguity is resolved to "not a type name" and if the programmer wants to use a type name which is nested inside anything that is dependent on a template parameter he/she has to use the typename
keyword in front of the name to let the compiler know that it should be treated as a type name.
Unfortunately there is an exception to that rule regarding nested dependent type names when using them inside a base class list or the base class identifier in a member initialization list.
template<typename T>
struct Base {
struct Nested {
Nested(int) {}
};
};
template<typename T>
struct Derived : public Base<T>::Nested { // typename not allowed here
Derived(int i)
: Base<T>::Nested(i) // nor here
{}
};
Btw: You should set your console client's charset to UTF-8, so you get ‘*’
instead of â*â
.