Sign in to follow this  
polaris2013

c++ templating woes

Recommended Posts

First let me explain some background to the problem so it's easier to understand why I'm doing this crazy thing. I'm making game and am currently working on collision. In order to reduce the number of collision tests (by about 80%), I divided up my objects into different containers based on what types of objects they can collide into. Now in order to keep my head from exploding, I'm trying to keep a uniform interface for each container, even though it stores different kinds of data. So my data containers are std::vectors (I know, I know... but I didn't have to write anything new!) Here's the problem: I want to write a function that takes an iterator to any of these vectors, and a reference to any of the vectors, and that function removes the correct object from the correct vector. So all the objects in my containers are all derived from CObjectBase. I was hoping all my containers would automatically upconvert to std::vector<CObjectBase*> for the purpose of this function, but they don't. In case I'm not being clear at all, here's the function:
E_VAL RemoveByIterator(std::vector<CObjectBase*> vect, std::vector<CObjectBase*>::iterator iter);
E_VAL CObjectList::RemoveByIterator(std::vector<CObjectBase*> vect, std::vector<CObjectBase*>::iterator iter)
{
	SafeDelete(*iter);
	vect.erase(iter);
	m_numVertices -= 6;
	m_numPolygons -= 2;

	return RET_OK;
}
I'm getting compiler errors that it cannot convert the parameters because my containers are not of type <CObjectBase*>, but they are of classes that are derived from CObjectBase*. How can I write this function?

Share this post


Link to post
Share on other sites
Would this work?

template < class A, class B >
E_VAL RemoveByIterator(std::vector<A*> vect, std::vector<B*>::iterator iter);


Note that I'm not sure on side-effects this might have, or other problems you might run into, since I don't know the rest of the dependencies or relation between vect and iter, or how you call them (is the type known at call site).

Share this post


Link to post
Share on other sites
To remove an element from std::vector<T>, it must be done by an iterator of that container (std::vector<T>::iterator), so you cant do a template function that uses a container with a different iterator, but you can do this (similar, but not the same thing):


template <class T>
E_VAL CObjectList::RemoveByIterator(std::vector<T> vect, typename std::vector<T>::iterator iter)
{
SafeDelete(*iter);
vect.erase(iter);
m_numVertices -= 6;
m_numPolygons -= 2;

return RET_OK;
}


Edit: Fixed typename.

Share this post


Link to post
Share on other sites
How the heck did you answer my question so fast! :)

The type *IS* always known from the call site, if that helps. Also both types are always the same, as in, class B == class A. However, I am getting a problem with your solution. Compiler says
Warning ::iterator "dependedent name is not a type"

Error Syntax error "identifier : iterator"

on the function definition. (Which is just like what you wrote, and removing the B does not change anything) And it repeats that error 3 times, btw.

edit: that was in response to antheus
edit 2: also tested jaiminho's fix, (with and without *'s on the T's), same error.

Share this post


Link to post
Share on other sites
template < class T >
E_VAL RemoveByIterator(std::vector<T*> vect, typename std::vector<T*>::iterator iter);

Share this post


Link to post
Share on other sites
OK, I get the idea of what you guys are doing to solve my problem, but for some reason it's not working with the iterator.

This compiles until I uncomment:
	template<class A>
E_VAL RemoveByIterator(std::vector<A> vect/*, std::vector<A>::iterator iter*/);

/*********/

template<class A>
E_VAL CObjectList::RemoveByIterator(std::vector<A> vect/*, std::vector<A>::iterator iter*/)
{
//SafeDelete(*iter);
//vect.erase(iter);
m_numVertices -= 6;
m_numPolygons -= 2;

return RET_OK;
}


I get the error I posted above when I uncomment the iterator. I'll repost here for convenience:
warning C4346: 'std::vector<A>::iterator' : dependent name is not a type
error C2061: syntax error : identifier 'iterator'

I get that warning+error 3 times on the header, and 1 time on the function itself.

edit: whether I have std::vector<A> or std::vector<A*> has no impact on compiler errors whatsoever.
edit again: unrelated question, how do you get that cool code box, antheus?
edit again again: just noticed that word "typename" !!!!!!!!

Share this post


Link to post
Share on other sites
As Antheus said in a previous post you have to add the typename in front of the iterator parameter to the function.

Share this post


Link to post
Share on other sites
Thanks, apparently I just can't read! Now it works! :)

edit:

Well, it compiles, but it doesn't work.... the erase line causes a crash every time.... says erase iterator is outside range

edit2: final fix:

Fiddled around with it, the first operand needed to be a reference and now it works, strangely there is no discernable difference between using A* compared to using A... anyone know why?

[Edited by - polaris2013 on June 10, 2007 7:58:27 PM]

Share this post


Link to post
Share on other sites
Quote:
Fiddled around with it, the first operand needed to be a reference and now it works, strangely there is no discernible difference between using A* compared to using A... anyone know why?


There is a difference, you just wont notice it if your working with vectors of pointers. When you use A the compiler will deduce that A = SomeType*, however when you use A* it will deduce A = SomeType (for a std::vector<SomeType*>) and so if you try to use the A* version with a std::vector<int> it will fail to compile because there is no type A for which A* = int.

From your description it sounds like the failure would be a desired behavious to prevent mistakes, and even better would be if it fails for types not derived from CObjectBase in which case I would use something like this:


#include <boost/type_traits/is_base_of.hpp>
#include <boost/enable_if.hpp>

template<typename T>
boost::enable_if<boost::is_base_of<CObjectBase, T>, E_VAL>::type
CObjectList::RemoveByIterator(std::vector<T*> vect, typename std::vector<T*>::iterator iter);



Also a note: If the order of the elements in the vector doesn't matter then you should be "swap and poping" (i.e. std::swap the element you want to remove with the last element then std::vector<T>::pop_back())

<rant>
Drop the C on the class names, you know its a class and the compiler will tell you if you try to use it incorrectly. Having the C is duplicated information which will have to be updated if you ever decide you want to make it something other then a class leading to additional maintenance costs.
</rant>

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