From: Jonathan Campbell on
It looks like I've stumbled over some misunderstanding of templates.
When I compile the code below (g++ (GCC) 4.1.2 20070502 (Red Hat
4.1.2-12) ), the first set of errors I get are:

ListT5.cpp: In function �std::string toString(const std::list<T,
std::allocator<_CharT> >&)�:
ListT5.cpp:18: error: expected `;' before �it�
ListT5.cpp:19: error: �it� was not declared in this scope
ListT5.cpp: In function �std::string toString(const std::list<T,
std::allocator<_CharT> >&) [with T = float]�:
ListT5.cpp:30: instantiated from here
ListT5.cpp:18: error: dependent-name �std::list<T,std::allocator<_CharT>
>::iterator� is parsed as a non-type, but instantiation yields a type
ListT5.cpp:18: note: say �typename std::list<T,std::allocator<_CharT>
>::iterator� if a type is meant

I do not understand the latter suggestion.

Any suggestions?

TIA,

Jon C.

--------------------------------------
#include <list>
#include <string>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <iterator>

using namespace std;

template <class T> string toString(const list<T>& l){
ostringstream os;
os<< "[ ";
list<T>::iterator it; // line 18
for(it = l.begin(); it!= l.end(); ++it){
os<< *it<< ' ';
}
os<< " ]"<< endl;
return os.str();
}

int main(){
list<float> x;

x.push_front(4.4); x.push_front(3.3); x.push_front(2.2);
x.push_front(1.1);
cout<< "x = "<< toString(x)<< endl;

// below works when all 'toString' stuff commented out
list<float>::iterator it;
cout<< "[ ";
for(it = x.begin(); it!= x.end(); ++it){
cout<< *it<< ' ';
}
cout<< " ]"<< endl;
----------------------------------------------------------------
From: Ben Cottrell on
Jonathan Campbell wrote:
> It looks like I've stumbled over some misunderstanding of templates.
> When I compile the code below (g++ (GCC) 4.1.2 20070502 (Red Hat
> 4.1.2-12) ), the first set of errors I get are:
>
> ListT5.cpp: In function �std::string toString(const std::list<T,
> std::allocator<_CharT> >&)�:
> ListT5.cpp:18: error: expected `;' before �it�
> ListT5.cpp:19: error: �it� was not declared in this scope
> ListT5.cpp: In function �std::string toString(const std::list<T,
> std::allocator<_CharT> >&) [with T = float]�:
> ListT5.cpp:30: instantiated from here
> ListT5.cpp:18: error: dependent-name �std::list<T,std::allocator<_CharT>
> >::iterator� is parsed as a non-type, but instantiation yields a type
> ListT5.cpp:18: note: say �typename std::list<T,std::allocator<_CharT>
> >::iterator� if a type is meant
>
> I do not understand the latter suggestion.
>
> Any suggestions?
>
> TIA,
>
> Jon C.
>
> --------------------------------------
> #include <list>
> #include <string>
> #include <iostream>
> #include <sstream>
> #include <algorithm>
> #include <iterator>
>
> using namespace std;
>
> template <class T> string toString(const list<T>& l){
> ostringstream os;
> os<< "[ ";
> list<T>::iterator it; // line 18

typename list<T>::iterator it;

If I'm not mistaken, the compiler is unable to implicitly determine
whether or not list<T>::iterator is a type, since list<T> is an
incomplete type at this stage. the typename keyword drops the
compiler a hint that list<T>::iterator is actually a type, and not
something else.
From: Jonathan Campbell on
Ben Cottrell wrote:
> Jonathan Campbell wrote:
>> It looks like I've stumbled over some misunderstanding of templates.
[...]
>>
>> template <class T> string toString(const list<T>& l){
>> ostringstream os;
>> os<< "[ ";
>> list<T>::iterator it; // line 18
>
> typename list<T>::iterator it;
>
> If I'm not mistaken, the compiler is unable to implicitly determine
> whether or not list<T>::iterator is a type, since list<T> is an
> incomplete type at this stage. the typename keyword drops the
> compiler a hint that list<T>::iterator is actually a type, and not
> something else.

Thanks. I changed the declaration of 'it'; after that did not compile, I
removed the 'const' from the argument, and then it did compile -- and
execute as expected.

template <class T> string toString(list<T>& l){
ostringstream os;
os<< "[ ";
typename list<T>::iterator it;
//list<T>::iterator it; // line 18
for(it = l.begin(); it!= l.end(); ++it){
os<< *it<< ' ';
}
os<< " ]"<< endl;
return os.str();
}

I am grateful, but I wish I could claim to be generally much the wiser.
I've not used a type 'variable' outside a class or function declaration
before, so I'm scratching my head a bit.

My question arose from the end of a series of 'back off to something
simpler' experiments that I've been doing to solve a problem in an
Iterator class for a List class that I'm adapting. I'll go off now and
see if I can apply this to the original problem.

Many thanks,

Jon C.
From: Ulrich Eckhardt on
Jonathan Campbell wrote:

> It looks like I've stumbled over some misunderstanding of templates.
> When I compile the code below (g++ (GCC) 4.1.2 20070502 (Red Hat
> 4.1.2-12) ), the first set of errors I get are:
>
> ListT5.cpp: In function 'std::string toString(const std::list<T,
> std::allocator<_CharT> >&)':
> ListT5.cpp:18: error: expected `;' before 'it'
> ListT5.cpp:19: error: 'it' was not declared in this scope
> ListT5.cpp: In function 'std::string toString(const std::list<T,
> std::allocator<_CharT> >&) [with T = float]':
> ListT5.cpp:30: instantiated from here

This is the important part:

> dependent-name 'std::list<...>::iterator' is parsed as a non-type,
> but instantiation yields a type

This directly refers to your use of 'list<T>::iterator' in your code, which
the compiler parses as a non-type but which eventually is a type instead.

This is just a rule of the C++ language that it is supposed to assume a
non-type there, but your instantiation resolves to a type instead. In
non-template functions, the compiler can actually figure out that it is a
type because all specialisations must be known at the time of use.

> note: say 'typename std::list<...>::iterator' if a type is meant.
>
> I do not understand the latter suggestion.

Well, it simply says that you should use 'typename list<T>::iterator'
instead of 'list<T>::iterator'.

> template <class T> string toString(const list<T>& l){
> ostringstream os;
> os<< "[ ";
> list<T>::iterator it; // line 18
> for(it = l.begin(); it!= l.end(); ++it){
> os<< *it<< ' ';
> }
> os<< " ]"<< endl;
> return os.str();
> }


Uli

From: Jonathan Campbell on
Jonathan Campbell wrote:
> It looks like I've stumbled over some misunderstanding of templates.

Thanks guys, that's moved me forward quite a bit.

I'm going to push my luck with another question.

In the List class below, I have used std::list as the implementation ---
just an experiment, I have a more difficult class that I want to clean
up and implement as a wrapper to std::list. (Incidentally, this
interface is from my own template List class which appears to work
perfectly fine.)

When I compile a program that #includes ListStd.h, I get the following
errors,

ListStd.h: In function �std::ostream& operator<<(std::ostream&, const
List<T>&)�:
ListStd.h:87: error: expected primary-expression before �template�
ListStd.h:87: error: expected `;' before �template�
ListStd.h:89: error: �it� was not declared in this scope

TIA again,

Jon C.



-----------------------------------------------------------
// ListStd.h
#ifndef LISTTH
#define LISTTH

#include <cassert>
#include <iostream>
#include <list>
#include <iterator>

template <class T> class List;
template <class T> std::ostream&
operator<<(std::ostream& os, const List<T>& l);

template <class T> class List{
friend std::ostream& operator<< <T>(std::ostream& os, const List<T>& l);
public:
List();
List(const List<T> & other);
~List();
List & operator = (const List<T> & rhs);
T front() const;
void push_front(T e);
void pop_front();
void clear();
bool empty() const;
int size() const;
private:
std::list<T> l_;
};
//-------------------------------------------------------------

/* guessing we do not need any of these

template <class T>List<T>::List(){}

template <class T>List<T>::List(const List<T> & source){
l_ = source.l_;
}

template <class T> List<T> & List<T>::
operator = (const List<T> & source){
l_ = source.l_;
return *this;
}

template <class T>List<T>::~List(){
l_.clear();
}
*/

template <class T> void List<T>::push_front(T e){
l_.push_front(e);
}

template <class T> T List<T>::front() const{
return l_.front();
}

template <class T> void List<T>::pop_front(){
l_.pop_front();
}

template <class T> void List<T>::clear(){
l_.clear();
}

template <class T>bool List<T>::empty() const{
return l_.empty();
}
template <class T>int List<T>::size() const{
return l_.size();
}

template <class T>
std::ostream& operator<< (std::ostream& os, const List<T>& l){
//std::list<T>iterator it; // line 86
template std::list<T>iterator it; // line 87
os<<"f[ ";
for(it = l.l_.begin(); it!= l.l_.end(); ++it){
os<< *it<< ' ';
}
os<<" ]b"<<std::endl;
return os;
}
#endif