Template question

Hello,

I have a problem which seems to be related to templates. Consider the following piece of code:

template<class T> int DataHelper::filter(std::vector<T*> instances, std::vector<bool> filter) {
int numberOfErasedInstances = 0;
int index = 0;
for (int n = 0; n < filter.size(); n++) {
if (filter[n]) {
index++;
} else {
T* t = instances[index];
instances.erase(instances.begin() + index);
delete t;
numberOfErasedInstances++;
}
}
return numberOfErasedInstances;
}

When calling it like this

int filteredOut = dataHelper.filter(writeVector, allowedInstances);

I get linker errors like this

MitgliedController.cpp:705: undefined reference to `int DataHelper::filter<Mitglied>(std::vector<Mitglied*, std::allocator<Mitglied*> >, std::vector<bool, std::allocator<bool> >)'

The compiler does not complain about anything. I'm rather new to templates, so maybe I miss something basic about templates - or I have some silly small mistake somewhere in my code...

What is your opinion? Would you expect this to work, and if not, why?

Thanks for any hints.

PS: The code is used within a Qt program. But neither the calling class nor the DataHelper is declared using the Q_OBJECT macro. So at least I see no reason why moc should do me some harm here. If it looks like it might do nevertheless, give me a hint ;-)
Is this definition in a header file?

Alternatively, the STL remove_if algorithm might be a nice fit for this application.
Please use code tags. So it looks like below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template<class T> int DataHelper::filter(std::vector<T*> instances, std::vector<bool> filter) 
{
  int numberOfErasedInstances = 0;
  int index = 0;
  for (int n = 0; n < filter.size(); n++) 
  {
      if (filter[n]) 
     {
         index++;
     } 
     else 
     {
         T* t = instances[index];
         instances.erase(instances.begin() + index);
         delete t;
         numberOfErasedInstances++;
     }
  }
  return numberOfErasedInstances;
}


Its a linker error. Meaning it compiles, but when linking the implementation, the linker cannot match it up. So if the code is in a .cpp file you may need to include the .cpp in the compile so the linker can link to the it.
Last edited on
It's in a cpp file, #including a header with the following class definition:

1
2
3
4
5
class DataHelper {

public:
	template<class T> int filter(std::vector<T*> instances, std::vector<bool> filter);
};


Ok, I did some further testing: Added some method void test() to DataHelper, and called it from the same place like I call filter. It does not complain about test! If I #include DataHelper.cpp separately, it doesn't complain about it either. So, my problem seems to be related to the template and at least I know a workaround for it. Although I don't actually understand what's going on here...
Try putting it in the header file. I know it sounds crazy...but that's where template definitions belong.
What moorecm means, is put the DEFINITION in the header file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class DataHelper {

public:
	template<class T> int filter(std::vector<T*> instances, std::vector<bool> filter) {
  		int numberOfErasedInstances = 0;
  		int index = 0;
  		for (int n = 0; n < filter.size(); n++) 
  		{
      			if (filter[n]) 
     			{
         			index++;
     			} 
     			else 
     			{
         			T* t = instances[index];
         			instances.erase(instances.begin() + index);
         			delete t;
				numberOfErasedInstances++;
			}
		}
		return numberOfErasedInstances;

	}
};


Also, your function call is incorrect.

int filteredOut = dataHelper<std::vector>(writeVector, allowedInstances);
At least, by my understanding of your variables (I didn't really read your code), that's what it should be. At the very least, I know you left out the template parameter.

Also, you can get the data type that an STL container is using by accessing one of the typedefs of its std::allocator object. So that template parameter isn't entirely necessary.
NGen wrote
Also, your function call is incorrect.

int filteredOut = dataHelper<std::vector>(writeVector, allowedInstances);


in this particular example, there is probably no need to specify template argument explicitly. The right type is chosen by the compiler via template argument deduction. And the right type is definetely not std::vector (which is not a type at all!).
Last edited on
Topic archived. No new replies allowed.