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:
Create a base class for all instantiations of Foo.
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() (e.g.: 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.
Related
Is there a way to call the constructor of a class, given the pointer-type of that class type as the template parameter?
MyClass<AnotherClass*> => how to call the default constructor of AnotherClass in MyClass?
This one does obviously not work (doesnt compile), because in GetNew the new T and the return type T don't fit together. What would be needed is some kind of "type dereferencing" to come to the class type, given the pointer type.
class AnotherClass
{};
template <class T>
class MyClass
{
public:
// this does obviously not compile
virtual T GetNew()
{
return new T; // how let T be AnotherClass* and to create an AnotherClass instance here?
}
};
int main()
{
// this does not compile:
MyClass<AnotherClass*> tmp; // here, AnotherClass is **pointer** type
AnotherClass* a = tmp.GetNew();
}
A workaround would be to use the class type as the template parameter and use poiter types as return types. But this changes the interface, so I would still like a solution to pointer template type.
class AnotherClass
{};
template <class T>
class MyClass2
{
public:
virtual T* GetNew()
{
return new T;
}
};
int main()
{
// this does work:
MyClass2<AnotherClass> tmp2; // here, AnotherClass is **not** pointer type
AnotherClass* b = tmp2.GetNew();
}
Another workaround could be to use a factory or similar, but I would like to use the default constructor without additional helping structures.
You can use std::remove_pointer to get the type pointed to.
Provides the member typedef type which is the type pointed to by T, or, if T is not a pointer, then type is the same as T.
E.g.
virtual T GetNew()
{
return new std::remove_pointer_t<T>;
}
If you require the parameter to MyClass to be a pointer, you can specialise it for pointers and leave it undefined for other types
template<typename>
class MyClass;
template<typename T>
class MyClass<T*>
{
public:
virtual T* GetNew()
{
return new T;
}
};
int main()
{
// MyClass2<AnotherClass> tmp1; // compile error
MyClass2<AnotherClass *> tmp2; // fine
AnotherClass* b = tmp2.GetNew(); // GetNew returns the exact type parameter
}
I have 2 classes A and B
class A is a template class
template<typename T>
class A
{
B getB(){return b;}
...
B b;
}
class B is a normal class that holds a pointer to class A
class B
{
...
template<typename T>
A<T> getA(){ return std::any_cast<A<T>>(a); }
template<typename T>
setA(A<T> a){ m_a = a; }
std::any m_a = nullptr;
}
but now when I want to go from A -> B -> A I have to specify twice the type
A<int>
.doSomeARelatedStuff()
.getB()
.doSomeBRelatedStuff()
.getA<int>()
.doSomeMoreARelatedStuff();
is it possible to eliminate the second template parameter in 'getA()' call?
logically I believe it is since I am already holding that data in A..
I looked around but didn't find any useful solution to my issue..
I thought about turning B into a template but I really wish there was a different solution to this.
BTW I am building a builder mechanism if the context helps..
When I inherit from a class the compiler has to know the definition of the base class in order to create it. But when I inherit from a template class using oneself (the inheriting class), how can the compiler create the code? It does not know the size of the class yet.
#include <iostream>
template <class T> class IFoo
{
public:
virtual T addX(T foo, double val) = 0;
// T memberVar; // uncomment for error
};
class Foo : public IFoo<Foo>
{
public:
Foo(double value)
: m_value(value) {}
Foo addX(Foo foo, double b) override
{
return Foo(foo.m_value + b);
}
double m_value;
};
int main()
{
Foo foo1(1);
Foo foo2 = foo1.addX(foo1, 1);
std::cout << foo2.m_value;
}
First I thought it works because it's an interface but it also works with a regular class.
When I store the template as a member i get an error that Foo is undefined, just as I expected.
The general concept here is called the Curiously Recurring Template Pattern or CRTP. Searching on that will get lots of hits. see: https://stackoverflow.com/questions/tagged/crtp .
However there is a simple explanation that likely answers your question without getting too much into CRTP. The following is allowed in C and C++:
struct foo {
struct foo *next;
...
};
or with two types:
struct foo;
struct bar;
struct foo {
struct bar *first;
...
};
struct bar {
struct foo *second;
...
};
So long as only a pointer to a struct or class is used, a complete definition of the type doesn't have to be available. One can layer templates on top of this in a wide variety of ways and one must be clear to reason separately about the type parameterizing the template and its use within the template. Adding in SFINAE (Substitution Failure Is Not An Error), one can even make templates that do no get instantiated because things cannot be done with a given type.
With this definition of template class IFoo, the compiler does not need to know the size of Foo to lay out IFoo<Foo>.
Foo will be an incomplete class in this context (not "undefined" or "undeclared") and usable in ways that any incomplete type can be used. Appearing in a member function parameter list is fine. Declaring a member variable as Foo* is fine. Declaring a member variable as Foo is forbidden (complete type required).
how can the compiler create the code?
Answering this question would be the same as answering this question: How can the compiler compile that?
struct Type;
Type func(Type);
Live example
How can you define a type that doesn't exist and yet declare a function that use that type?
The answer is simple: There is no code to compile with that actually use that non-existing type. Since there is no code to compile, how can it even fail?
Now maybe you're wondering what is has to do with your code? How does it make that a class can send itself as template parameter to it's parent?
Let's analyze what the compiler see when you're doing that:
struct Foo : IFoo<Foo> { /* ... */ };
First, the compile sees this:
struct Foo ...
The compiler now knows that Foo exists, yet it's an incomplete type.
Now, he sees that:
... : IFoo<Foo> ...
It knows what IFoo is, and it knows that Foo is a type. The compiler now only have to instanciate IFoo with that type:
template <class T> struct IFoo
{
virtual T addX(T foo, double val) = 0;
};
So really, it declares a class, with the declaration of a function in it. You saw above that declaring a function with an incomplete type works. The same happens here. At that point, Your code is possible as this code is:
struct Foo;
template struct IFoo<Foo>; // instanciate IFoo with Foo
So really there's no sorcery there.
Now let's have a more convincing example. What about that?
template<typename T>
struct IFoo {
void stuff(T f) {
f.something();
}
};
struct Foo : IFoo<Foo> {
void something() {}
};
How can the compiler call something on an incomplete type?
The thing is: it don't. Foo is complete when we use something. This is because template function are instantiated only when they are used.
Remember we can separate functions definition even with template?
template<typename T>
struct IFoo {
void stuff(T f);
};
template<typename T>
void IFoo<T>::stuff(T f) {
f.something();
}
struct Foo : IFoo<Foo> {
void something() {}
};
Great! Does it start looking exactly the same as your example with the pure virtual function? Let's make another valid transformation:
template<typename T>
struct IFoo {
void stuff(T f);
};
struct Foo : IFoo<Foo> {
void something() {}
};
// Later...
template<typename T>
void IFoo<T>::stuff(T f) {
f.something();
}
Done! We defined the function later, after Foo is complete. And this is exaclty what happens: The compiler will instanciate IFoo<Foo>::stuff only when used. And the point where it's used, Foo is complete. No magic there either.
Why can't you declare a T member variable inside IFoo then?
Simple, for the same reason why this code won't compile:
struct Bar;
Bar myBar;
It doesn't make sense declaring a variable of an incomplete type.
Here a brief example of a code that works. It helps to introduce the actual question.
The specifiers for the visibility are the same used in the real code.
class Base {
public:
using foo = int;
virtual ~Base() { }
protected:
static foo bar() noexcept {
static foo v = 0;
return v++;
}
};
template<class Derived>
class Class: public Base {
static foo get() noexcept {
static foo v = bar();
return v;
}
};
int main() { }
It follows the previous example, even though slightly modified.
A template parameter has been added to the base class and the derived one has been updated accordingly.
This one doesn't compile.
template<typename T>
class Base {
public:
using foo = int;
virtual ~Base() { }
protected:
static foo bar() noexcept {
static foo v = 0;
return v++;
}
};
template<class Derived, typename T>
class Class: public Base<T> {
static foo get() noexcept {
static foo v = bar();
return v;
}
};
int main() { }
The error is quite clear indeed and the problem is not to solve it:
main.cpp:18:12: error: ‘foo’ does not name a type
static foo get() noexcept {
^
main.cpp:18:12: note: (perhaps ‘typename BaseComponent<T>::foo’ was intended)
The actual question is: why foo is not visible without a scope specifier in the second example?
I mean, Class is derived from Base<T>, that is (at least in my mind) a fully defined type, thus foo should be part of the base class and thus visible to the derived one, as it happens in the first example.
It follows an example that, according to what I guess of the problem, actually compiles and should not, or at least should behave like the previous one:
template <typename T>
struct B {
using foo = T;
};
struct D: public B<int> {
static foo bar;
};
int main() {
B<int> *b = new D;
}
Could it be due to the fact that the derived class is not a templated one in this case?
Honestly, it seems to me a bit strange, because the foo type is part of the base class that is still a templated one, so it shouldn't be much different from the previous one.
It goes without saying that I'm wrong, but I cannot figure out what's wrong in my thoughts.
Thank you in advance for the help.
That's because of name lookup rules. If your base class is a template, the unqualified name in base is not resolved. The reason is that later in your code you may have a template specialization of that base which doesn't define the name, or for which the name means something completely different. It's too complicated for the compiler to figure out whether you have a specialization, and if so, whether your name means the same thing in it. So it prefers to defer the name lookup. To make the compiler "believe you", then you need to either use a qualified name, or this->name instead (for members, not for typedefs), and the compiler will resolve the name.
I'm having a little problem with my classes. I have two classes which both use template methods, therefore I have to put it in the header. Here is an example. I'd like it to compile properly without the "forward declaration incomplete" problem. I understand what is wrong but I can't figure how to correct this. Thank you guys.
class.h
class A;
class B;
class A
{
B *foo;
template <class T>
void func()
{
foo->fanc();
}
}
class B
{
A *foo;
void fanc();
template <class T>
void osef()
{
foo->func<int>();
}
}
You have a circular dependence. You can not declare an object of incomplete class. You can solve this by declaring either pointers or references to the incomplete class.
class A
{
B* foo;
or
class A
{
B& foo;
On the later case you have to initialize the reference with the member initialization list of the constructor.
If you are using pointer then you should move the definition of the memeber function after the definition of the incomplte class.
class A;
class B;
class A
{
B* foo;
template <class T>
void func();
};
class B
{
// ...
};
template <class T>
inline void A::func()
^^^^^^ // If you need to include the header in more than one source file.
{
foo->fanc();
}