views:

125

answers:

5
template <class T>
class List
{
    public:

        List();
        ~List();

        ...

    protected:

        template <class T> struct Item
        {
            struct Item* next;
            T data;
        };

        ...

        struct Item<T>* allocate();
};

template <class T>
struct Item<T>* List<T>::allocate() // error here
{
    ...
    return object; // struct Item<T>*
}

how can i do that?

+2  A: 

Write:

template <class T>
struct List<T>::Item* List<T>::allocate()
// etc

The :: operator tells the compiler that Item is a nested class of List.

Tom Smith
Not correct yet :) Should be `List<T>::Item*`. Also, an extra `typename` keyword might be necessary (unless, that `struct` makes it unnecessary). P.S. No, it is not necessary with `struct`.
AndreyT
+3  A: 

You are reusing the T type name. Use a different one: template <class U> struct Item { ... (or remove templatization from Item all together - it looks like you are just fine with outer template parameter):

template <class T>
class List
{
    ...
    protected:

        struct Item
        {
            Item* next;
            T data;
        };

        Item* allocate() { return object; }
};
Nikolai N Fetissov
Why is this downvoted? It's correct... no need for Item to be declared as a template as well, since the intent is to reuse the same type as the class template was instantiated as.
Nick Meyer
@Nick Meyer: (I didn't downvote it.) But, firstly, it doesn't answer the question, which was about out-of-class definition. And, secondly, how do you know the intent? In the OP, `Item` is an independent nested template, which can be used for other purposes in other contexts. Nothing says that it willalways be instantitated with the same argument as the "outer" class.
AndreyT
And how using same type name for nested template helps then?
Nikolai N Fetissov
@Nikolai N Fetissov: What name are you talking abouyt? The parameter name `T`? It doesn't help. It is an error. The parameter name in the inner template must be different from the outer template's parameters. Apparently, in this case OP not only doesn't know the answer, the OP doesn't even know the question.
AndreyT
Yep, that was the point.
Nikolai N Fetissov
+3  A: 
AndreyT
You're quite right! Now changed.
Tom Smith
Doesn't it have to be `List<T>::Item<T>*` because both List and Item are templates?
sepp2k
@sepp2k: You are right. I think I finally got all the bits and pieces right.
AndreyT
+1  A: 

You need to qualify the type: List::Item<T>

You can use the non-qualified name of the type when you are inside the class declaration, or inside the argument list or body of each of the member functions of the type (or derived classes), but not for the return type. When the compiler resolves the return type, it does not yet know that you are defining a member of the List template, and as such it will not look inside that class scope.

This is an interesting point of how compilers work that has actually influenced some changes in the upcoming standard to allow auto like return type definitions:

template<typename T, typename U>
auto sum( T lhs, U rhs ) -> delctype(lhs+rhs) 
{ return lhs+rhs; }

The compiler is able to deduce types T and U once the arguments are present, but you cannot tell it that the return type is decltype(lhs+rhs) as return type since neither lhs nor rhs are yet in scope. While this is a C++ only problem, it has its roots in the same problem you are facing: the scope of the return type is external to the scope of the method that is being declared.

David Rodríguez - dribeas
+1  A: 

The problem is deeper in fact:

You don't have to declare Item as being template, because it's a nested class within a template class it has access to T.

template <class T>
class List
{
public:

private:
  struct Item { ... };
};

And then you would define access like so:

template <class T>
typename List<T>::Item List<T>::access(...) {}

The point here is that List is a template class, so its parameters must be specified, while once T is specified for List it's not necessary to precise it once again.

Note typename ;)

Matthieu M.
thx a lot. it works now
ohohoho