templates and cyclic dependencies

L

Leslaw Bieniasz

Cracow, 20.09.2004

Hi,

I am posting this again, because my previous message dated
18.09. disappeared from the list (someone has cancelled it ? why ??).

I have a problem with compiling the following construction involving
cross-calls of class template methods, with additional inheritance.
I want to have three class templates:

------------------------------------------
in file "Model.h":

#include "Data.h"

template<class T> class Model
{
....
void Read(Data<T> *data);
virtual int Get_Info(void);
};

template<class T>
void Model<T>::Read(Data<T> *data)
{
....
T something = data->Get(); // Note the Data method call
}

template<class T>
int Model<T>::Get_Info(void)
{
....
}

template class Model<float>;
template class Model<double>;

---------------------------------------
in file "Model1.h":

#include "Model.h"

template<class T> class Model1 : public Model<T>
{
....
virtual int Get_Info();
};

template<class T>
int Model1<T>::Get_Info(void)
{
....
}

template class Model1<float>;
template class Model1<double>;

----------------------------------------
in File "Data.h":

#include "Model.h"

template<class T> class Data
{
Data(Model<T> *model);
....
T Get(void);
};

template<class T>
Data<T>::Data(Model<T> *model)
{
....
int info = model->Get_Info(); // Note the virtual Model method call
}

template<class T>
T Data<T>::Get(void)
{
....
}

template class Data<float>;
template class Data<double>;

------------------------------------------
In the calling unit, file "Caller.h" I want to be able to do something
like this:

#include "Model.h"
#include "Model1.h"
#include "Data.h"

template<class T> class Caller
{
....
void call(void);
};

template<class T>
Caller<T>::call(void)
{
....
Model<T> *model = new Model1<T>();
....
Data<T> *data = new Data<T>(model);
....
model->Read(data);
....
}

template class Caller<float>;
template class Caller<double>;
---------------------------------------------------

I cannot figure out where to #include the various files and/or
where to provide forward class template declarations in order to avoid
compiler errors caused by nested inclusions of the header files, as
indicated. I have tried various combinations, such as not including
the headers, but using only forward declarations, or including the
headers after class declarations but before the method bodies. Nothing
helps.

I would appreciate any advice, also how to possibly redesign
the above code in order to have the same functionality and logic.
(I hope I have not introduced any spurious errors into the above
description, I am just writing this from memory, not from the
real code. In the real code certainly there are no typos or similar
errors. Please pay attention to the problem structure, not to details
of the statements). I use BCB 4.0, if this has any meaning.

Sincerely,

L.B.

*-------------------------------------------------------------------*
| Dr. Leslaw Bieniasz, |
| Institute of Physical Chemistry of the Polish Academy of Sciences,|
| Department of Electrochemical Oxidation of Gaseous Fuels, |
| ul. Zagrody 13, 30-318 Cracow, Poland. |
| tel./fax: +48 (12) 266-03-41 |
| E-mail: (e-mail address removed) |
*-------------------------------------------------------------------*
| Interested in Computational Electrochemistry? |
| Visit my web site: http://www.cyf-kr.edu.pl/~nbbienia |
*-------------------------------------------------------------------*
 
V

Victor Bazarov

Leslaw said:
I am posting this again, because my previous message dated
18.09. disappeared from the list (someone has cancelled it ? why ??).

Nobody but you can cancel your message (usually). Check with your
ISP.
I have a problem with compiling the following construction involving
cross-calls of class template methods, with additional inheritance.
I want to have three class templates:

------------------------------------------
in file "Model.h":

#include "Data.h"

template<class T> class Model
{
...
void Read(Data<T> *data);

The compiler doesn't usually need to know what 'Data<T>' is here.
Since you're declaring the function with the pointer, you may just
forward-declare 'Data' at the beginning of 'Model.h'.
virtual int Get_Info(void);
};

template<class T>
void Model<T>::Read(Data<T> *data)
{
...
T something = data->Get(); // Note the Data method call

Here you'd usually need to know what 'Data' is since you're using
a member of it. The compiler needs to know the layout of the class
template.
}

template<class T>
int Model<T>::Get_Info(void)
{
...
}

template class Model<float>;
template class Model<double>;

If you have explicit instantiations, you may hide all the implementation
in a C++ file. It's going to be even simpler from the inclusion point
of view.
---------------------------------------
in file "Model1.h":

#include "Model.h"

template<class T> class Model1 : public Model<T>
{
...
virtual int Get_Info();
};

template<class T>
int Model1<T>::Get_Info(void)
{
...
}

template class Model1<float>;
template class Model1<double>;

----------------------------------------
in File "Data.h":

#include "Model.h"

template<class T> class Data
{
Data(Model<T> *model);

Same here. Since you declared a use of a pointer to Model<T>, you
just need to let the compiler know that Model<T> is a class template.
[Forward-]Declare the template at the beginning of the file instead
of including 'Model.h'.
...
T Get(void);
};

template<class T>
Data<T>::Data(Model<T> *model)
{
...
int info = model->Get_Info(); // Note the virtual Model method call
}

template<class T>
T Data<T>::Get(void)
{
...
}

template class Data<float>;
template class Data<double>;

------------------------------------------
In the calling unit, file "Caller.h" I want to be able to do something
like this:

#include "Model.h"
#include "Model1.h"
#include "Data.h"

template<class T> class Caller
{
...
void call(void);
};

template<class T>
Caller<T>::call(void)
{
...
Model<T> *model = new Model1<T>();
...
Data<T> *data = new Data<T>(model);
...
model->Read(data);
...
}

template class Caller<float>;
template class Caller<double>;
---------------------------------------------------

I cannot figure out where to #include the various files and/or
where to provide forward class template declarations in order to avoid
compiler errors caused by nested inclusions of the header files, as
indicated. I have tried various combinations, such as not including
the headers, but using only forward declarations, or including the
headers after class declarations but before the method bodies. Nothing
helps.

This is what should help: begin by forward-declaring everything and
then add the inclusions only when it is absolutely necessary. My
suspicion is that if you split your code into declarations and member
definitions, and then leave the declarations in the headers and move
the definitions in source files, you shouldn't have to include any
headers into headers, only into source files.

The compiler should know what to do because you provide the explicit
instantiations of your templates.

V
 
L

Leslaw Bieniasz

Cracow, 22.09.2004

Hello,

I have a problem with compiling the following construction involving
cross-calls of class template methods, with additional inheritance.
I want to have three class templates:

------------------------------------------
in file "Model.h":

#include "Data.h"

template<class T> class Model
{
...
void Read(Data<T> *data);

The compiler doesn't usually need to know what 'Data<T>' is here.
Since you're declaring the function with the pointer, you may just
forward-declare 'Data' at the beginning of 'Model.h'.
virtual int Get_Info(void);
};

template<class T>
void Model<T>::Read(Data<T> *data)
{
...
T something = data->Get(); // Note the Data method call

Here you'd usually need to know what 'Data' is since you're using
a member of it. The compiler needs to know the layout of the class
template.
}

template<class T>
int Model<T>::Get_Info(void)
{
...
}

template class Model<float>;
template class Model<double>;

If you have explicit instantiations, you may hide all the implementation
in a C++ file. It's going to be even simpler from the inclusion point
of view.
---------------------------------------
in file "Model1.h":

#include "Model.h"

template<class T> class Model1 : public Model<T>
{
...
virtual int Get_Info();
};

template<class T>
int Model1<T>::Get_Info(void)
{
...
}

template class Model1<float>;
template class Model1<double>;

----------------------------------------
in File "Data.h":

#include "Model.h"

template<class T> class Data
{
Data(Model<T> *model);

Same here. Since you declared a use of a pointer to Model<T>, you
just need to let the compiler know that Model<T> is a class template.
[Forward-]Declare the template at the beginning of the file instead
of including 'Model.h'.
...
T Get(void);
};

template<class T>
Data<T>::Data(Model<T> *model)
{
...
int info = model->Get_Info(); // Note the virtual Model method call
}

template<class T>
T Data<T>::Get(void)
{
...
}

template class Data<float>;
template class Data<double>;

------------------------------------------
In the calling unit, file "Caller.h" I want to be able to do something
like this:

#include "Model.h"
#include "Model1.h"
#include "Data.h"

template<class T> class Caller
{
...
void call(void);
};

template<class T>
Caller<T>::call(void)
{
...
Model<T> *model = new Model1<T>();
...
Data<T> *data = new Data<T>(model);
...
model->Read(data);
...
}

template class Caller<float>;
template class Caller<double>;
---------------------------------------------------

I cannot figure out where to #include the various files and/or
where to provide forward class template declarations in order to avoid
compiler errors caused by nested inclusions of the header files, as
indicated. I have tried various combinations, such as not including
the headers, but using only forward declarations, or including the
headers after class declarations but before the method bodies. Nothing
helps.


This is what should help: begin by forward-declaring everything and
then add the inclusions only when it is absolutely necessary. My
suspicion is that if you split your code into declarations and member
definitions, and then leave the declarations in the headers and move
the definitions in source files, you shouldn't have to include any
headers into headers, only into source files.

The compiler should know what to do because you provide the explicit
instantiations of your templates.

This will not work, because according to the current C++ standard all
template stuff (except perhaps for the explicit instantiations) MUST go
into headers, otherwise the code cannot be compiled. This is the
problem. The errors are detected while parsing the definitions of the
class template methods, not while parsing the class template declaration (in the
latter case forward declarations are indeed sufficient), because in the
definitions not only pointers or references to other classes occur,
but method calls.

L.B.


*-------------------------------------------------------------------*
| Dr. Leslaw Bieniasz, |
| Institute of Physical Chemistry of the Polish Academy of Sciences,|
| Department of Electrochemical Oxidation of Gaseous Fuels, |
| ul. Zagrody 13, 30-318 Cracow, Poland. |
| tel./fax: +48 (12) 266-03-41 |
| E-mail: (e-mail address removed) |
*-------------------------------------------------------------------*
| Interested in Computational Electrochemistry? |
| Visit my web site: http://www.cyf-kr.edu.pl/~nbbienia |
*-------------------------------------------------------------------*
 
V

Victor Bazarov

Leslaw said:
[...]
This will not work, because according to the current C++ standard all
template stuff (except perhaps for the explicit instantiations) MUST go
into headers, otherwise the code cannot be compiled.

I don't want this to go into "must -- must not" type of argument, but
I don't have time to provide you with examples either. I will just say
that if you define the template class (with all members _declared_) and
use _explicit_instantiations_ in the same header, you _don't_ need all
the member definitions in the same header. If you know what I am talking
about, you can try it yourself. Sapienti sat.

Otherwise, use a compiler that supports 'export' keyword. IOW, what you
said about "according to the current C++ standard" only shows your poor
knowledge of the standard. No offense intended.

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top