template function problem

Started by
13 comments, last by Sync Views 16 years, 2 months ago
object.h

template<typename obj_type>int instance_count();

object.cpp

template<typename obj_type> 
int instance_count()
{
	int count = 0;
	for(std::vector<object *>::iterator it = cgm::object_list.begin(); it != cgm::object_list.end(); it++)
	{	
		if (!(*it)) continue;
		if (!(*it)->active) continue;
		if (!dynamic_cast<obj_type*>(*it)) continue;
		count++;
	}
	return count;
}

somewhere else...

int count = instance_count<obj_target>();

Why do I get linker errors saying it can't link my function? It's clearly there and there are no spelling mistakes or anything...
Advertisement
If thats exactly your code, I believe you need the word <Class MyClass> in the tags for the template.
Unless your compiler supports the export keyword, and I'm willing to bet that yours doesn't, then you can't put the definition of a template in a separate source file without explicit instantiation for specific types. Without explicit instantiation, the complete definition of the template needs to be available at point of instantiation, which means, in effect, that the definition needs to go into the header. (Or an inline file of some sort, etc.)
The problem is then I'd need to make all my object stuff global which I really don't want to do...especially for a static lib...

Is there anyway I can have the template function in the header and have it pass the object type to a another function someother way?
template<typename obj_type> int instance_count(){	int count = 0;	for(std::vector<object *>::iterator it = cgm::object_list.begin(); it != cgm::object_list.end(); it++)	{			if (!(*it)) continue;		if (!(*it)->active) continue;		if (!dynamic_cast<obj_type*>(*it)) continue;		count++;	}	return count;}


Put the above in the header. It doesn't change anything whatsoever from what you're doing now.

The function above doesn't exist in lib - it's part of included header file. It'll be instantiated where you call it.

Templates are just a different form of macros.

Even more, you don't need to include vector or object_list or anything similar in the header file. You just need to make sure they are included at point of use.

Templated functions are just templates, pieces of text.

When you call such a function, that particular specialization will be instantiated in the compilation unit where you're using it. This is why one common counter-argument against templates is code bloat. Templates can get instantiated many times across different compilation units.
if it's in the header though it will fail against every cpp except object.cpp because cgm::object_list doesn't exist anywhere else... I don't really want to make stuff like that global...
Quote:Original post by Sync Views
The problem is then I'd need to make all my object stuff global which I really don't want to do...especially for a static lib...

Is there anyway I can have the template function in the header and have it pass the object type to a another function someother way?


Something like this:
// header fileint instance_count(const std::type_info &);template<typename obj_type> int instance_count(){     return instance_count(typeid(obj_type));}// source fileint instance_count(const std::type_info &info){	int count = 0;	for(std::vector<object *>::iterator it = cgm::object_list.begin(); it != cgm::object_list.end(); it++)	{			object *ptr = *it;		if(ptr && ptr->active && info == typeid(*ptr))                {		    count++;                }	}	return count;}


While this appears to work, it is considered a poor idea to look up the dynamic type of an object instance. The whole point of inheritance is that it shouldn't matter.

One could also note that we are basically re-writing std::count_if, so we could use that instead:
// header fileint instance_count(const std::type_info &);template<typename obj_type>int instance_count(){     return instance_count(typeid(obj_type));}// source file#include <algorithm>struct Predicate{    const std::type_info *info;    Predicate(const std::type_info &info):info(&info){}    bool operator()(const object *ptr) const    {        return (ptr && ptr->active && (*info) == typeid(*ptr));    }};int instance_count(const std::type_info &info){    return std::count_if(cgm::object_list.begin(),cgm::object_list.end(),Predicate(info));}
Is there a better way other than template functions or type id's to pass a type and check if that type is the same as the type a pointer is pointing to? Taking into acount inheritance etc?

eg
bool objecttype(void* obj, class obj_type);{    if(obj == obj_type) return true);    else return false;}


I only really need to check if the item I'm pointing to is either the same as the objtype or a child of it...
Yes, and it's really quite simple: don't lose that type information in the first place. Universal base classes are a bad thing.
Quote:Original post by Sync Views
Is there a better way other than template functions or type id's to pass a type and check if that type is the same as the type a pointer is pointing to? Taking into acount inheritance etc?

eg
*** Source Snippet Removed ***

I only really need to check if the item I'm pointing to is either the same as the objtype or a child of it...


Templates are compile-time polymorphism. You need to provide the type you're using.

If you want inheritance and all that, you need run-time polymorphism, where you do not know the type ahead.

Decide which you want. Mixing both is generally not needed, especially not in the way you want.

void * is always bad, except under certain circumstances for internal usage. But in general, you should never (in C++) need this in user API.

Quote:I only really need to check if the item I'm pointing to is either the same as the objtype or a child of it...


Why not imply that?
void foo(BaseType * bar){  // whatever, but bar is of type BaseType};


Here you'd get compile-time check if you pass incorrect instance.

Obviously, bars will come from, for example, std::vector<BaseType *>. C++ provides type safety. Use it.

This topic is closed to new replies.

Advertisement