Sign in to follow this  
c_olin

Writing a wrapper for std::list...

Recommended Posts

I've been writing wrappers for some of the std data types in C++. All has gone well for std::vector, std::map, but I'm having trouble dealing with std::list::iterators:
#include <list>

template <class T>
class List {

public:

    /* This part will not compile unless I give an exact
       Type instead of 'T' */
    std::list<T>::iterator insert();


private:

    std::list<T> _list;

};

As I wrote in the source above. I'm having trouble getting std::list<T>::iterator to compile... It compiles fine with std::list<float>::iterator, it is just the template type that is throwing it off. Any ideas?

Share this post


Link to post
Share on other sites
Quote:
Original post by c_olin
I've been writing wrappers for some of the std data types in C++. All has gone well for std::vector, std::map, but I'm having trouble dealing with std::list::iterators:


Why on earth would you do such a thing?! Do you also varnish your windows?

Quote:
I'm having trouble getting std::list<T>::iterator to compile... It compiles fine with std::list<float>::iterator, it is just the template type that is throwing it off.


Always give the compiler error. This response is a shot in the dark.

The compiler will assume that std::list<T>::iterator is not the name of a type unless you tell it so:


// ...
typename std::list<T>::iterator insert();
// ...




or, ideally:


// ...
typedef typename std::list<T>::iterator iterator;
// ...
iterator insert();
// ...




Even more ideally, just use std::list as is.

Share this post


Link to post
Share on other sites
Sounds like a tremendous waste of time. If you post your wrapper, we could critique your choices.

The reason why std::list and friends even exists is so that every C++ programmer who needs to use common data structures (and algorithms) can do so in any program. The alternative is something like in C, where every program often has these re-implemented, with varying APIs. Hence the important word 'standard'.

Share this post


Link to post
Share on other sites
I too question why you're writing these wrappers. If you seek a deeper understanding of the underlying container, try rolling your own. If you just want an easy to use, pre-existing container, what's wrong with using a vanilla std::list/vector/whatever, such that you need to wrap it yourself?

Share this post


Link to post
Share on other sites
Quote:
Original post by c_olin
Mostly because I do plan in the future to write my own implementations of these structures... and also for cleanliness.

Thanks for the help.


Writing your own implementation for learning purposes while trying to conform to the (tried and tested) API of std::list would be a more admirable task, IMO. Don't forget to post your implementations here for comments/problems!

Share this post


Link to post
Share on other sites
If you just want to make room for the possibility that you'll use your own list class in the future, just use typedefs; you don't need to write wrapper classes.

Share this post


Link to post
Share on other sites
One of the main reasons why I have been making these "wrapper" classes is to include functions that the standard library does not contain and that I need to do a lot.

For example. I'm not using smart pointers so I needed a function to loop through and delete all pointers in a given list/map/vector. So this saves me a lot of code. It also makes my code much more readable (to me) as I really dislike the std library naming conventions. Maybe "wrapper" isn't the correct terminology.

Rephrase: I'm writing list/vector/map classes extending upon the std libraries versions.

But thanks for the help you guys. I got it to compile.

Share this post


Link to post
Share on other sites
Quote:
Original post by c_olin
For example. I'm not using smart pointers so I needed a function to loop through and delete all pointers in a given list/map/vector.
For what it's worth, Boost has a set of 'pointer container' classes that offer functionality similar to what you describe above. (Of course, they follow the standard library naming conventions, and so might not be to your liking :)

Share this post


Link to post
Share on other sites
Yeah I looked into Boost and I decided it wasn't for me.

Maybe I take naming conventions too seriously but it makes code so much easier to look at when all functions have a certain naming convention and all types have a certain naming convention, etc.

Either way, it has made my code smaller and easier to read.

BTW your cml library has made my life much easier ;)

Share this post


Link to post
Share on other sites
Even if you want to add functionality on top of the standard library classes, you should consider writing non-member functions for them. There are a lot of reasons for that, but one big one is that if you do it right, you can use the same functions for multiple containers without limiting it to one object. This is one reason why the algorithm header exists and those functions are members of the individual container classes.

For example, if you want to delete all the pointers in a container, you could do something like:

template <typename T> void deleter(T t) { delete t; }
template <typename Container>
void delete_all(Container & cont) {
std::for_each(cont.begin(), cont.end(), &deleter<Container::value_type>);
cont.clear();
}

std::list<int *> a;
// do stuff
delete_all(a);

Share this post


Link to post
Share on other sites
Again, this is code where the template contains a dependant type. It requires use of typename to compile:

template <typename T> void deleter(T t) { delete t; }

template <typename Container>
void delete_all(Container & cont) {
std::for_each(cont.begin(), cont.end(), &deleter<typename Container::value_type>);
cont.clear();
}





Dropping boost is not a good idea, it is a fantastic source. Many of the things it has within it are non-trivial for your average programmer to write.

Share this post


Link to post
Share on other sites
As regards the standard library and preferring nonmember nonfriends there's a good old GotW on the topic. I'd have to agree that wrapping is the wrong approach here. And if you're serious about modern C++ then the sooner you embrace things like the standard library and boost the better off you'll be for it. The whole issue of naming conventions is really just a herring. My coding style doesn't match the style used in the standard library or boost either. I actually prefer it that way - it makes it much easier for me to look at the code and know exactly where the pieces come from and what they're designed to do.

Share this post


Link to post
Share on other sites
Quote:
Original post by c_olin
Yeah I looked into Boost and I decided it wasn't for me.

Maybe I take naming conventions too seriously but it makes code so much easier to look at when all functions have a certain naming convention and all types have a certain naming convention, etc.


Do you think you would be looking at the Boost code often, or at all? If so, why? Have you looked at the implementation code for the containers you're "wrapping"? If not, why not?

Quote:
One of the main reasons why I have been making these "wrapper" classes is to include functions that the standard library does not contain and that I need to do a lot.


In addition to things like Boost, a lot of this functionality is supplied by... the standard library. Just not in the places you might expect. Check out <algorithm>, for example.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this