traits help

R

Rex_chaos

Hi there,
I am learning template programming and there is a problem about
traits. Now consider a container and an iterator. Here is the code

// tag for const iterator and non-const iterator
struct non_const_iterator_tag {};
struct const_iterator_tag {};

// traits
template <typename T,
typename tag=non_const_iterator_tag>
struct Iter_traits
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
};

// For const iterator ...
template <typename T>
struct Iter_traits<T, const_iterator_tag>
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
typedef const T& reference;
};


//Iter is an iterator

template <typename T, typename tag=non_const_iterator_tag>
class Iter
{
typedef typename Iter_traits<T, tag>::value_type value_type;
typedef typename Iter_traits<T, tag>::reference reference;
public:
Iter(T *c) :cont(c) {...}

// copy constructor to shift the non-const iterator to const
iterator
Iter(const Iter<T, non_const_iterator_tag>& it) :cont(it.c)
{...}

private:
T *cont;
};

// Container is a container.

template <typename T>
class Container
{
...
public:
typedef Iter<T> iterator;
typedef Iter<T, const_iterator_tag> const_iterator;

iterator begin() {...};
const_iterator begin() const {...};
iterator end() {...};
const_iterator end() const {...};
private:
T *data;
...
};

int main(void)
{
Container<int> c;

// copy constructor should be actived here
Container<int>::const_iterator cit=c.begin();
return 0;
}

An error occurs while compliation.

`int* Iter<int, non_const_iterator_tag>::cont' is private

I don't know why. It seems that it's due to the copy constructor.
Please help!


BTW, if I define begin() outside the class. e.g.

template <typename T>
Container<T>::iterator Container<T>::begin(void)
{
...
}

The compiler will give a warning:
`typename Container<T>::iterator' is implicitly a typename
mplicit typename is deprecated, please see the documentation for
details

Is that anything wrong? Should I do something to prevent that warning?

Thanks in advance.
 
V

Victor Bazarov

Rex_chaos said:
I am learning template programming and there is a problem about
traits. Now consider a container and an iterator. Here is the code

// tag for const iterator and non-const iterator
struct non_const_iterator_tag {};
struct const_iterator_tag {};

// traits
template <typename T,
typename tag=non_const_iterator_tag>
struct Iter_traits
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
};

// For const iterator ...
template <typename T>
struct Iter_traits<T, const_iterator_tag>
{
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
typedef const T& reference;
};


//Iter is an iterator

template <typename T, typename tag=non_const_iterator_tag>
class Iter
{
typedef typename Iter_traits<T, tag>::value_type value_type;
typedef typename Iter_traits<T, tag>::reference reference;
public:
Iter(T *c) :cont(c) {...}

// copy constructor to shift the non-const iterator to const
iterator

Why do you say "to shift the ..."? It's just a copy constructor.
Iter(const Iter<T, non_const_iterator_tag>& it) :cont(it.c)
{...}

private:
T *cont;
};

// Container is a container.

The comment above seems unnecessary. The class name is self-
documenting.
template <typename T>
class Container
{
...
public:
typedef Iter<T> iterator;
typedef Iter<T, const_iterator_tag> const_iterator;

iterator begin() {...};
const_iterator begin() const {...};
iterator end() {...};
const_iterator end() const {...};

Drop the semicolons after the closing curly braces. The code
looks dirty due to them.
private:
T *data;
...
};

int main(void)
{
Container<int> c;

// copy constructor should be actived here
Container<int>::const_iterator cit=c.begin();

Why should it? c.begin() returns 'Container<int>::iterator'.
return 0;
}

An error occurs while compliation.

`int* Iter<int, non_const_iterator_tag>::cont' is private

I don't know why. It seems that it's due to the copy constructor.

No. It's due to the fact that you don't have a constructor that
constructs a const_iterator from a "regular" iterator.
Please help!

Define a parameterised constructor that would convert 'iterator'
into 'const_iterator'.
BTW, if I define begin() outside the class. e.g.

template <typename T>
Container<T>::iterator Container<T>::begin(void)
{
...
}

The compiler will give a warning:
`typename Container<T>::iterator' is implicitly a typename
mplicit typename is deprecated, please see the documentation for
details

Is that anything wrong? Should I do something to prevent that warning?

You should declare such function this way:

template<typename T>
typename
Container<T>::iterator Container<T>::begin()
{
...


Victor
 
G

Grzegorz Sakrejda

Hi there,


//Iter is an iterator

template <typename T, typename tag=non_const_iterator_tag>
class Iter
{
typedef typename Iter_traits<T, tag>::value_type value_type;
typedef typename Iter_traits<T, tag>::reference reference;
public:
Iter(T *c) :cont(c) {...}

// copy constructor to shift the non-const iterator to const
iterator
Iter(const Iter<T, non_const_iterator_tag>& it) :cont(it.c)
{...}


this part looks suspicious. I don't know what it.c is but it is probably
private and
const_iterator do not have access to it .
 
R

Rex_chaos

Why do you say "to shift the ..."? It's just a copy constructor.
Yes. But the copy constructor is not a common one, because the
incomming class is a non_const_iterator wihile the destination class
is a const_iterator
Drop the semicolons after the closing curly braces. The code
looks dirty due to them.
Sorry, I forgot to erase the semicolons.
Why should it? c.begin() returns 'Container<int>::iterator'.
You want to assign it to 'Container<int>::const_iterator'.
Those two are different types.
Take a look at the Container<T> class, I have two functions for
begin(), one returns the iterator and other returns the
const_iterator. When I call
Container<int>::const_iterator cit=c.begin();
I hope the later begin() will be called. However, it won't. So I have
a copy constructor in my code.

No. It's due to the fact that you don't have a constructor that
constructs a const_iterator from a "regular" iterator.
But I have a copy constructor for this purpose.
 
R

Rex_chaos

this part looks suspicious. I don't know what it.c is but it is probably
private and
const_iterator do not have access to it .
Try this code, and you see that in (copy) constructor, the class
itself can also access the private data.

class Test
{
public:
Test() {...}
Test(const Test& t) :data(t.data) {}
private:
int data;
};
 
V

Victor Bazarov

Rex_chaos said:
Try this code, and you see that in (copy) constructor, the class
itself can also access the private data.

class Test
{
public:
Test() {...}
Test(const Test& t) :data(t.data) {}
private:
int data;
};

In this code, in the copy c-tor, 't' and '*this' are of the
_same_ type. In your attempt, iterator and const_iterator
are not even related.

Victor
 

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

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top