views:

80

answers:

3

The following compiles in GCC:

cvec.hpp:

template <class T>
class cvec : public deque<T>
{    
   class deque<T>::iterator Find(T);
};

cvec.cpp:

template <class T> 
class deque<T>::iterator cvec<T>::Find(T element)
{

}

In Visual C++, get error C2242 "typedef name cannot follow class/struct/union. I changed "class" in the header file to "typename", but receive error C3860 - template argument list must list parameters in the order used in the template param list. There is only one parameter in this case, T. Unless the compiler is confused about Find(T element)?

A: 

This works for me in 2010:

#include <deque>

template <class T>
class cvec : public std::deque<T>
{    
public:
  typedef typename std::deque<T>::iterator iterator; 
  iterator Find(T element);
};

template <class T> 
typename cvec<T>::iterator cvec<T>::Find(T element)
{
  return std::deque<T>::iterator();
}

using namespace std;

int main()
{
  cvec<int> c;
  c.Find(1);

  return 0;
}
ngoozeff
Works in VS2008 as well
Praetorian
Works with VS2005 too.
Gangadhar
Great, tested this with the posted code in 2008. Hadn't thought about typedef'ing the iterator, than using this has the return type for find.
Naish44
+1  A: 

What is this supposed to mean in the header:

class deque<T>::iterator Find(T);

You are not declaring a class. The typename keyword would be valid here, but class makes no sense.

And the same is true in the .cpp file:

template <class T> 
typename deque<T>::iterator cvec<T>::Find(T element)

is correct, class isn't.

Apart from this, it really looks like what you're trying to do is a horrible idea. std::deque already has a find function. It works. It is correct. It is efficient. There is no need to reinvent it.

The standard library containers are also not designed to be derived from. They don't have virtual destructors.

All you're achieving (apart from the compile errors) is that you're going to end up with a buggy, less efficient container class that'll confuse other C++ programmers because it doesn't use the idiomatic interface.

jalf
A: 

This should really be a comment, but I'm making it an answer so that I can format it for readability.

@jalf and @dvl -- As @dvl said above, none of the std containers have virtual destructors. Why does that matter?

Let's say you derive a class "X" from from std::deque.

class X : public std::deque<int>
{
    // whatever ...
};

Let's now say that you have an "X" object, pointed to by a base pointer.

std::deque<int> *p = new X;

and you delete it

delete p;

The destructor for the derived class X will not be called, which can lead to lots of problems.

Your options:
1. Don't derive from std containers. Make them data members and write wrappers to expose the functionality.
2. Only derive from std containers if the derived class has no destructor and no data members with destructors.
3. If you derive from a std container, never refer to it by a base pointer.

After you create a class, it is sometimes hard to know how the class might be used in the future. For that reason, many developers stick strictly to option "1". Personally I permit deriving from a std container as long as it is well documented and used with care.

Michael J