5

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’

jackhab
  • 17,128
  • 37
  • 99
  • 136
  • 3
    As a side note: Please read this about using underscore in identifiers. http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier/228797#228797 – Martin York Oct 13 '09 at 18:39
  • 1
    Short version: "Don't start identifier names with underscores" – jalf Oct 13 '09 at 19:03
  • Long version: Underscores followed by a capital letter are reserved for the compiler. Double underscores followed by anything are reserved for the compiler as well. – GManNickG Oct 13 '09 at 22:03
  • Possible duplicate of [Where and why do I have to put the "template" and "typename" keywords?](http://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords) – RiaD Dec 27 '15 at 01:00

1 Answers1

17

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 :])

GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • 1
    Notice there's an error on your CSafeSet class template. You also need typename to define the iterators types because they are also dependent. Example: typedef **typename** container_type::iterator iterator_type; Without that typename it shouldn't compile in a standard conformant compiler. I could guess that you tried it in Visual Studio (version before 2008, when I think that was fixed), which erroneoulsy accepted such lines without typename. – Leandro T. C. Melo Oct 13 '09 at 18:49
  • I didn't try at all, actually. Thanks for pointing that out, I was being silly (very common) :) – GManNickG Oct 13 '09 at 22:02
  • BTW, I thought using upper-case names will emphasize it's not an original STL class. I am not sure I am going to implement *all* std::set methods in my CSafeSet. – jackhab Oct 14 '09 at 08:14