The typedefs in standard container?

S

Saeed Amrollahi

Dear all
hi

There are a lot of typedefs in standard library containers. For
example:
template<class T, class A = allocator<T> >
class vector {
typedef T value_type;
typedef A allocator_type;
typedef typename A::pointer pointer; // pointer to
element
typedef typename A::const_pointer const_pointer;
typedef typename A::reference reference; // reference to element
typedef typename A::const_reference const_reference;
// ...
};
There are similar declarations in other containers like valarray,
list, map, ...
What are they? What are the benfits of such declarations?

Thanks in advance,
-- Saeed Amrollahi
 
P

Pascal J. Bourguignon

Saeed Amrollahi said:
Dear all
hi

There are a lot of typedefs in standard library containers. For
example:
template<class T, class A = allocator<T> >
class vector {
typedef T value_type;
typedef A allocator_type;
typedef typename A::pointer pointer; // pointer to
element
typedef typename A::const_pointer const_pointer;
typedef typename A::reference reference; // reference to element
typedef typename A::const_reference const_reference;
// ...
};
There are similar declarations in other containers like valarray,
list, map, ...
What are they? What are the benfits of such declarations?


They can be used by templates: they are compilation time attributes of
the class (or template class), that other template may use.

template <class Container> class X{
void f(Container& c){
Container::iterator iterator=c.begin();
Container::value_type element=(*iterator);
...
}
}


They can also be used by the programmer, so less code has to be
changed when the type is changed. A lot of algorithms don't care
whether a container is a list or a vector, or whether they contain
int, strings or floats. So there's no reason to program them
depending on these types, it's better to refer to write:

typedef ...<...> Container;

void f(Container& c){
Container::iterator iterator=c.begin();
Container::value_type element=(*iterator);
...
}

So if you want to switch from one type to another later, you just have
to change the typedef line, and everything else works all the same.
 
J

Jerry Coffin

[ ... ]
There are a lot of typedefs in standard library containers. For
example:
template<class T, class A = allocator<T> >
class vector {
typedef T value_type;
typedef A allocator_type;
typedef typename A::pointer pointer; // pointer to
element
typedef typename A::const_pointer const_pointer;
typedef typename A::reference reference; // reference to element
typedef typename A::const_reference const_reference;
// ...
};
There are similar declarations in other containers like valarray,
list, map, ...
What are they? What are the benfits of such declarations?

They're used primarily by algorithms that manipulate (data in) the
containers. For example, let's consider adding together the elements
in a container. For non-generic code, that's pretty easy:

int sum(int *x, size_t size) {
int sum=0;

for (size_t i=0; i<size; i++)
sum += x;
return sum;
}

Now consider generalizing that to sum a collection of objects of any
type instead:

template <class collection>
T sum(collection const &c) {
T sum = T();

for (size_t i=0; i<c.size(); i++)
sum +=c;
return sum;
}

Right now, I've used "T" as the type of object, but the question is:
"How do we get T?" In a general sense, that doesn't have an answer.
The collection itself will be have a template parameter that
specifies the type:

std::vector<int> ints;

We're being passed a vector, but what we want is the type over which
the vector has been instantiated. C++ doesn't provide a way to
retrieve that as part of the language, so instead the standard
containers include a typedef to tell you what it is.

Needless to say, that's not the only type we might be interested in
about a container -- so the container has typedef's for other types
that might become interesting as well.

As a sidenote, most algorithms operate on containers via iterators, so
iterators normally have typedef's to pass the same information
through from the container to the algorithm.
 
S

Saeed Amrollahi

They can be used by templates: they are compilation time attributes of
the class (or template class), that other template may use.

template <class Container> class X{
   void f(Container& c){
      Container::iterator   iterator=c.begin();
      Container::value_type element=(*iterator);
      ...
    }

}

They can also be used by the programmer, so less code has to be
changed when the type is changed.   A lot of algorithms don't care
whether a container is a list or a vector, or whether they contain
int, strings or floats.  So there's no reason to program them
depending on these types, it's better to refer to write:

typedef ...<...>  Container;

void f(Container& c){
  Container::iterator   iterator=c.begin();
  Container::value_type element=(*iterator);
  ...

}

So if you want to switch from one type to another later, you just have
to change the typedef line, and everything else works all the same.

So, because we have no access to template parameter T in
container class, we declare such typedefs and use them
via typename.
Another advantage of such declaration is changing code will be easier.

Thank you Pascal
-- Saeed Amrollahi
 
S

Saeed Amrollahi

[ ... ]




There are a lot of typedefs in standard library containers. For
example:
template<class T, class A = allocator<T> >
class vector {
  typedef T value_type;
  typedef A allocator_type;
  typedef typename A::pointer pointer;               // pointer to
element
  typedef typename A::const_pointer const_pointer;
  typedef typename A::reference reference;     // reference to element
  typedef typename A::const_reference const_reference;
  // ...
};
There are similar declarations in other containers like valarray,
list, map, ...
What are they? What are the benfits of such declarations?

They're used primarily by algorithms that manipulate (data in) the
containers. For example, let's consider adding together the elements
in a container. For non-generic code, that's pretty easy:

int sum(int *x, size_t size) {
        int sum=0;

        for (size_t i=0; i<size; i++)
                sum += x;
        return sum;

}

Now consider generalizing that to sum a collection of objects of any
type instead:

template <class collection>
T sum(collection const &c) {
        T sum = T();

        for (size_t i=0; i<c.size(); i++)
                sum +=c;
        return sum;

}

Right now, I've used "T" as the type of object, but the question is:
"How do we get T?" In a general sense, that doesn't have an answer.
The collection itself will be have a template parameter that
specifies the type:

std::vector<int> ints;

We're being passed a vector, but what we want is the type over which
the vector has been instantiated. C++ doesn't provide a way to
retrieve that as part of the language, so instead the standard
containers include a typedef to tell you what it is.

Needless to say, that's not the only type we might be interested in
about a container -- so the container has typedef's for other types
that might become interesting as well.

As a sidenote, most algorithms operate on containers    via iterators, so
iterators normally have typedef's to pass the same information
through from the container to the algorithm.

--
    Later,
    Jerry.- Hide quoted text -

- Show quoted text -


So, because we have no access to template parameter T in
container class, we declare such typedefs and use them
via typename.

Thank you Jerry
-- Saeed Amrollahi
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top