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();
}
Related
I have a class template that implements a number of functions. I want to be able to also add specialized version of this class which has only a few functions that override those of the base, when a specific type is declared. I know I could achieve this with a class template and explicit specializations of it. However I also want to:
Have the explicit specializations uniquely named, similar to how a base and derived class are uniquely named.
Call the Base functions from an instantiated Derived object, either inside a Derived function, or explicitly as below with obj1.Foo
This is the (simplified) example code I am trying to make work:
In myClasses.h
template<typename T>
class Base
{
public:
void Foo (T& input);
virtual void Bar (T& input);
}
template<>
class Derived : public Base<int>
{
public:
void Bar (int& input) override;
}
In myClasses.cpp
template<typename T>
Base::Foo(T& input) { // Do something generic }
template<typename T>
Base::Bar(T& input) { // Do something generic }
template<>
Derived::Bar(int& input) { // Do something int-dependent }
In main.cpp
int main()
{
Base<int> obj1 = new Derived();
obj1.Foo(input); // Runs Base::Foo
obj1.Bar(input); // Runs Derived::Bar
}
However this code fails with the explicit specialization of non-template Derived error, among others. I've read a lot of StackOverflow threads to get me this far, but I haven't found any that have helped me make this compile. So my questions are:
Is combining class templates with class inheritance possible in this way?
Why does the compiler label the Derived class a non-template despite me explicitly using that keyword?
What is the correct syntax that will make this code work? (assuming what I am trying to do is possible)
EDIT: Following the suggesting of HTNW, I can turn Derived into a regular class by removing the template<> prefix. This will allow everything to compile up to obj1.Foo(input). It seems that the instantiated Derived class can't find or access the base Foo function.
Thanks to ravnsgaard and HTNW for the helpful suggestions which got me to a solution. The key was to remove the template<> keyword from the Derived class (because I wanted it to be a class and not a class template) and declaration of Base<int> at the end of the source file. So the working code looks like this:
In myClasses.h
template<typename T>
class Base
{
public:
void Foo (T& input);
virtual void Bar (T& input);
}
class Derived : public Base<int>
{
public:
void Bar (int& input) override;
}
in myClasses.cpp
template<typename T>
Base::Foo(T& input) { // Do something generic }
template<typename T>
Base::Bar(T& input) { // Do something generic }
Derived::Bar(int& input) { // Do something int-dependent }
template class Base<int>; // VERY IMPORTANT.
In main.cpp
int main()
{
Base<int> &&obj1 = Derived();
obj1.Foo(input); // Runs Base::Foo
obj1.Bar(input); // Runs Derived::Bar
}
In particular, without the template class Base<int>; declaration at the end of myClasses.cpp, the call to obj1.Foo will fail with an error complaining that Derived has no such function.
I have this very simple class using CRTP:
template <typename DerivedType, void (DerivedType::*updateMethod)() = &DerivedType::update>
class UpdatableBase {};
class MyClass : private UpdatableBase<MyClass> {
public:
void update() {
}
};
int main() {
return 0;
}
Which, when compiled with g++ test.cpp -std=c++14, gives this:
test.cpp:2:85: error: no member named 'update' in 'MyClass'
template <typename DerivedType, void (DerivedType::*updateMethod)() = &DerivedType::update>
~~~~~~~~~~~~~^
test.cpp:5:25: note: in instantiation of default argument for 'UpdatableBase<MyClass>' required here
class MyClass : private UpdatableBase<MyClass> {
^~~~~~~~~~~~~~~~~~~~~~
1 error generated.
Why does it say there's "no member named 'update' in 'MyClass'"? There very clearly is.
This is a very common problem with CRTP: the compiler instantiates the base class definition before it reads the derived class definition.
The work around is to only use the definition of the derived class inside base class member definition:
#include <type_traits>
template <typename DerivedType, class DelayedParameter = void>
class UpdatableBase {
public:
//definition of members of templates are instantiated when needed!
void update(){
if constexpr(std::is_same_v<DelayedParameter,void>)
static_cast<DerivedType>(this)->update();
else
(static_cast<DerivedType*>(this)->*DelayedParameter::value)();
}
};
class MyClassDelayedParameter;
class MyClass:public UpdatableBase<MyClass,MyClassDelayedParameter>
//the compiler only instantiate the definition of the base class:
//it will only instantiate the DECLARATION of the base class members.
{
public:
void update();
};
//Here MyClass is defined so we can access its member.
struct MyClassDelayedParameter:
std::integral_constant<void(MyClass::*)(),&MyClass::update>
{};
//UpdatableBase<...>::update DEFINITION is instantiated here. At this point
//of instantiation, MyClass and MyClassDelayedParameter are defined.
int main() {
MyClass a;
UpdatableBase<MyClass,MyClassDelayedParameter>& b=a;
b.update();
return 0;
}
DEMO
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.
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.
I'm working on a little project to understand how C++ templates work.
Basically, I have something like:
class Base{
public:
MyOperation<Base> operate(Base x){ return MyOperation<Base>(x); } //error here
};
//...
template<class B>
class MyOperation : public Base{
public:
B b;
MyOperation(B b_){ b = b_; }
};
When I try compiling my program, I get an error (Error C2143, missing ';' before '<'). Is it because I can't have MyOperation as return type of funcion operate()?
Thank you in advance.
The syntax for declaring a template is template<class B> (or equivalently, template<typename B>).
Also there is a circular reference: Base references MyOperation (return type and inside the operate function). So MyOperation would need to be defined before Base.
But MyOperation also references Base (base class).
For the base class, and for the use inside a function, a full definition is needed. But for the return type, an incomplete type is enough. So MyOperation would need to be predeclared before Base, like:
template<class B> class MyOperation;
And in addition, operate() needs to be defined (not declared) outside of class Base { ... }, after the definition of MyOperation. The correct code would be:
// pre-declaration of MyOperation
template<class B> class MyOperation;
// definition of Base class
class Base {
public:
// declaration of Base::operate member function
// MyOperation<Base> is incomplete type here
MyOperation<Base> operate(Base x);
};
// definition of MyOperation class template
template<class B>
class MyOperation : public Base{
public:
B b;
MyOperation(B b_){ b = b_; }
};
// definition ofBase::operate member function
inline MyOperation<Base> Base::operate(Base x) {
return MyOperation<Base>(x);
}
Base::operate needs to be inline if the definition is in a header file, otherwise there will be multiple linker symbols if the header is included by multiple source files.
If it is not inline (better if it is a large function), then the definition should go in a source file.