Reputation: 22074
I'm implementing an observer pattern as a template, and wanted one class to have different listener types being attached. The problem is that it doesn't seem possible to use the same template in a single class multiple times with different types. As far as I understand it, it should be possible, because the method names would have different types anyway, so they should be mangled into a different names. However the error I get is not at linktime, but at compiletime, so I would like to know what I'm doing wrong or if this is not possible at all.
To demonstrate the problem I wrote a SSCE:
#include <iostream>
#include <string>
template<typename T>
class Comparator
{
public:
Comparator(void) { mCounter = 0; };
virtual ~Comparator(void) {};
bool equals(T oFirst, T oSecond)
{
mCounter++;
if(oFirst != oSecond)
return false;
return true;
}
int getCounter(void)
{
return mCounter;
}
private:
int mCounter;
};
class TestClass :
public Comparator<int>,
public Comparator<void *>
{
public:
TestClass(void) {};
virtual ~TestClass(void) {};
};
int main(int argc, char *argv[])
{
TestClass t1;
TestClass *t2 = &t1;
TestClass *t3 = new TestClass();
int v1 = 1;
int v2 = 2;
bool b = t1.equals(v1, v2);
std::cout << b << std::endl;
std::cout << t1.equals(&t1, &t2) << std::endl;
std::cout << t1.getCounter() << std::endl;
delete t3;
return 0;
}
When I compile this with gcc (using Cx11 option) I get the following error:
||=== Build: Debug in CPPMingW (compiler: GNU GCC Compiler) ===|
D:\src\c\Tests\CPPMingW\main.cpp||In function 'int main(int, char**)':|
D:\src\c\Tests\CPPMingW\main.cpp|38|error: request for member 'equals' is ambiguous|
D:\src\c\Tests\CPPMingW\main.cpp|12|note: candidates are: bool Comparator<T>::equals(T, T) [with T = void*]|
D:\src\c\Tests\CPPMingW\main.cpp|12|note: bool Comparator<T>::equals(T, T) [with T = int]|
D:\src\c\Tests\CPPMingW\main.cpp|38|error: expected primary-expression before 'int'|
D:\src\c\Tests\CPPMingW\main.cpp|38|error: expected ';' before 'int'|
D:\src\c\Tests\CPPMingW\main.cpp|39|error: request for member 'equals' is ambiguous|
D:\src\c\Tests\CPPMingW\main.cpp|12|note: candidates are: bool Comparator<T>::equals(T, T) [with T = void*]|
D:\src\c\Tests\CPPMingW\main.cpp|12|note: bool Comparator<T>::equals(T, T) [with T = int]|
D:\src\c\Tests\CPPMingW\main.cpp|35|warning: unused variable 'v1' [-Wunused-variable]|
D:\src\c\Tests\CPPMingW\main.cpp|36|warning: unused variable 'v2' [-Wunused-variable]|
||=== Build failed: 4 error(s), 2 warning(s) (0 minute(s), 1 second(s)) ===|
In this example I don't really see why it should be ambigous, because in both calls the datatype is well defined and totally different from the other template specialization. I would expect the errof from getCounter()
because this is really not determinable.
Upvotes: 4
Views: 140
Reputation: 28178
You expect equals
from your base classes to participate in overload resolution as if they were both defined in your derived class, but unfortunately it doesn't work that way (I'm not sure why not).
You can either explicitly call the version of equals
you want:
t1.Comparator<int>::equals(v1, v2);
Or you can add this in your derived class (public section):
using Comparator<int>::equals;
using Comparator<void*>::equals;
Which should allow the 2 equals functions from your base classes to do the standard overload resolution. You could also achieve the same thing by writing the 2 equals functions in the derived class and having each one call the appropriate base class equals
.
Just to note: Comparator<int>
and Comparator<void*>
are entirely separate classes. They know nothing of eachother. This would behave the same if they were not templates but had different names as well.
Upvotes: 4