Reputation: 374
I have a template class which has a pointer to the same class (but not necessarily using the same type). Here is an example:
template<class T>
class Foo{
Foo(){}
Foo* a;
template<class U>
void bar(Foo<U>* b){a=b;}
}
When I use it in my main function, everything seems to be working until I use a different template for the argument.
int main(){
Foo<double> f1;
Foo<double> f2;
f1.bar(&f1);// no Errors
Foo<bool> f3;
Foo<double> f4;
f3.bar(&f4);//Error : cannot convert 'Foo<double>*' to 'Foo<bool>*'
}
Is there anyway I can define a pointer in class Foo
that has a "generic" pointer to the same class in it?
Upvotes: 3
Views: 3676
Reputation: 31
How about adding an extra parameter to the template:
template<class T, class U=T>
class Foo {
public:
Foo() {}
Foo<U>* a;
void bar(Foo<U>* b) { a = b; }
};
int main(){
Foo<bool, double> f3;
Foo<double> f4;
f3.bar(&f4);
return 0;
}
If the second template parameter is not specified, it will be equal to the first one. And this means that your pointer "a" will point to an object of the same type as "this". If the second parameter is specified and it's different from the first one, your pointer "a" will point to a different type.
It's not a generic solution because you cannot change the second type once the object is created. But if you know from the start that
Foo<bool>
needs to point to
Foo<double>
it might work.
Upvotes: 0
Reputation: 24738
Another possibility besides the solutions with a common base class consists of defining the type of the a
data member in Foo
as void *
instead of Foo *
. That way any data pointer can be assigned to it (this one would be a generic pointer):
template<class T>
class Foo {
public:
Foo(){}
void* a;
template<class U>
void bar(Foo<U>* b){a=b;}
...
};
Then, you could define the following member template convert_ptr()
to convert the pointer back to its original type:
template<class T>
class Foo {
...
template<class U>
Foo<U>* convert_ptr() {
return reinterpret_cast<Foo<U>*>(a);
}
};
As an example:
int main(){
Foo<bool> f1;
Foo<double> f2;
f2.bar(&f1);
Foo<bool> *p = f2.convert_ptr<bool>();
}
Bear in mind that not using the right template instance of convert_ptr()
(e.g.: not casting a
back to the pointer of the right type) will result in undefined behavior.
Upvotes: 0
Reputation: 20631
Is there anyway I can define a pointer in class Foo that has a "generic" pointer to the same class in it?
That's what you already have:
Foo* a;
What you actually want, I think, is a pointer to any instantiation of Foo
. That's not possible. The question is: why do you want that? If you say exactly what you are trying to achieve, maybe you can get a more useful answer.
One possibility might be to use a base class:
class Base {
// whatever common functionality you want in Foo goes here
};
template<class T>
class Foo : public Base {
Foo(){}
Base* a;
template<class U>
void bar(Foo<U>* b){a=b;}
}
Whether this will work for you is hard to say until you provide more information about what you are trying to achieve. I think we are hitting an XY problem here.
Upvotes: 1
Reputation: 206567
Is there anyway I can define a pointer in class Foo that has a "generic" pointer to the same class in it?
What you have is correct. What you are expecting to see is founded on probably a misunderstanding.
Foo<bool>
and Foo<double>
are totally different classes. Type/class templates allow you to use the compiler to generate new types but they themselves are not classes.
If you had to generate the classes manually, you would have:
class Foo_bool{
Foo_bool(){}
Foo_bool* a;
...
};
class Foo_double{
Foo_double(){}
Foo_double* a;
...
};
With that, it's easy to see why you can't use:
Foo_bool a;
Foo_double b;
a.a = &b; // Not allowed
That is no different than using:
Foo<bool> a;
Foo<double> b;
a.a = &b; // Not allowed
The closest you can come to achieving your goal is:
Foo
.Simple program that demonstrates the concept:
class FooBase
{
public:
virtual ~FooBase() {}
};
template<class T>
class Foo : public FooBase {
public:
Foo(){}
template<class U>
void bar(Foo<U>* b){a=b;}
private:
FooBase* a; // Note the change. This is not Foo* any longer.
};
int main()
{
Foo<bool> a;
Foo<double> b;
a.bar(&b);
}
Upvotes: 2