Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble with templates in c++: "Expected primary expression before `>` token"

Tags:

c++

templates

I have the following code in a project I am doing for class. I have been having trouble with the print statement for hours, and I could not find what I needed on the internet.

Here is my templated class definition:

template <class T>
class oset {
    template <class U>
    class node { 
    .....
    };
    .....
public:
   template <class U>
    class iter {
        node<U> *pos;          // node _before_ the one with this->operator*
        // constructor is private:
        iter(node<U>* n) : pos(n) { }
    friend class oset<U>; 
    ....
    };
 private:
    iter<T> start;         // initialized in the constructors below
    iter<T> finish;        // initialized in the constructors below

 public:
    iter<T> begin() {
        return start;
    }
    iter<T> end() {
        return finish;
    }
....
};

Then the problem I'm having is in print:

template <class S>
void print(oset<S>& OS) {
    for (oset<S>::iter<S> i = OS.begin(); i != OS.end(); ++i) { 
        // ^-- error is on previous line
        cout << *i << " ";
   }
   cout << endl;
}

When I try to compile with g++ I get the following error message:

oset.cc:276: error: expected primary-expression before ‘>’ token

oset.cc:276: error: ‘i’ was not declared in this scope

The problem is in the commented line. The '>' token giving problems is the one directly before the first i. For some reason it does not like the <S>. If i get rid of the <S> it tells me it expects a ';' before the i

I honestly have no idea what is causing the problem. I am getting very frustrated and any help would be highly appreciated. Thanks!

like image 943
Garrett Rosenblatt Avatar asked Dec 10 '11 05:12

Garrett Rosenblatt


1 Answers

for (oset<S>::iter<S> i = OS.begin(); i != OS.end(); ++i) { //error this line

You've to use typename and template here:

for (typename oset<S>::template iter<S> i = OS.begin(); i != OS.end(); ++i) 

Note that none of the following would work:

oset<S>::iter<S> i              //error
typename oset<S>::iter<S> i     //error
oset<S>::template iter<S> i     //error

Your situation is such that you've to use both keywords : typename as well as template:

typename oset<S>::template iter<S> i  //ok

Why you need both keywords here, is explained by @Johannes in this topic:

  • Where and why do I have to put the "template" and "typename" keywords?

Few advices and improvements

  • Make the iterator class a non-template. Use T wherever you're using U in its definition.
  • Also rename the class from iter to iterator. Make it look like standard container/iterator, so that you could use it in agorithms defined in <algorithm>.

That is, your class should look like this:

class iterator {
    node<T> *pos;
    iterator(node<T>* n) : pos(n) { }
    friend class oset<T>; 
};

Then in for loop, you would only need typename as:

typename oset<S>::iterator i //ok
like image 62
Nawaz Avatar answered Oct 24 '22 02:10

Nawaz