简体   繁体   中英

Generic template pointer in template class

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?

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:

  1. Create a base class for all instantiations of Foo .
  2. Store a pointer to the base class.

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);
}

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.

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() (eg: not casting a back to the pointer of the right type) will result in undefined behavior.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM