Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

error returning std::set<T>::iterator in template

Tags:

c++

templates

stl

I'm making a template wrapper around std::set. Why do I get error for Begin() function declaration?

template <class T>
class CSafeSet
{
    public:
        CSafeSet();
        ~CSafeSet();

        std::set<T>::iterator Begin();

    private:
        std::set<T> _Set;
};

error: type ‘std::set, std::allocator<_CharT> >’ is not derived from type ‘CSafeSet’

like image 467
jackhab Avatar asked Oct 13 '09 17:10

jackhab


People also ask

What is the difference between STD iterator and iterator iterator?

std::iterator is a helper to define the iterator traits of an iterator. std::iterator is a template, that takes 5 template parameters: Those 5 names sound familiar, right? Those template types correspond to the 5 types required by the STL on iterators. The job of std::iterator is to expose those types.

Should we stop using std:: iterator in C++?

std::iterator is deprecated, so we should stop using it. Indeed, the next step after deprecation could be total removal from the language, just like what happened to std::auto_ptr. But contrary to std::auto_ptr, the alternative to std::iterator is trivial to achieve, even in C++03: just implement the 5 aliases inside of your custom iterators.

Why is the STL deprecated for iterators?

So it does not concern the types that the STL expects from an iterator, and neither does it concern the idea that an iterator should provide information to the code that uses it. What is deprecated is the technique of inheriting from std::iterator to define those types.

How is STD:: iterator_traits implemented in GCC?

If you peek into libstdc++, used by gcc, you’ll see that std::iterator_traits is implemented as: This implies that, as soon as you try to access one member, such as ::iterator_category for example, the whole structured and all its typedefs are instantiated.


1 Answers

Try typename:

template <class T>
class CSafeSet
{
    public:
        CSafeSet();
        ~CSafeSet();

        typename std::set<T>::iterator Begin();

    private:
        std::set<T> _Set;
};

You need typename there because it is dependent on the template T. More information in the link above the code. Lot's of this stuff is made easier if you use typedef's:

template <class T>
class CSafeSet
{
    public:
        typedef T value_type;
        typedef std::set<value_type> container_type;
        typedef typename container_type::iterator iterator_type;
        typedef typename container_type::const_iterator const_iterator_type;

        CSafeSet();
        ~CSafeSet();

        iterator_type Begin();

    private:
        container_type _Set;
};

On a side note, if you want to be complete you need to allow CSafeSet to do the same thing as a set could, which means using a custom comparer and allocator:

template <class T, class Compare = std::less<T>, class Allocator = std::allocator<T> >
class CSafeSet
{
    public:
        typedef T value_type;
        typedef Compare compare_type;
        typedef Allocator allocator_type;

        typedef std::set<value_type, compare_type, allocator_type> container_type;
        typedef typename container_type::iterator iterator_type;
        typedef typename container_type::const_iterator const_iterator_type;

        // ...
}

And a last bit of advice, if you are going to create a wrapper around a class, try to follow the same naming conventions as where the class came from. That is, your Begin() should probably be begin() (And personally I think C before a class name is strange but that one is up to you :])

like image 100
GManNickG Avatar answered Sep 19 '22 06:09

GManNickG