templates and cyclic dependencies

Discussion in 'C++' started by Leslaw Bieniasz, Sep 20, 2004.

  1. 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: |
    *-------------------------------------------------------------------*
    | Interested in Computational Electrochemistry? |
    | Visit my web site: http://www.cyf-kr.edu.pl/~nbbienia |
    *-------------------------------------------------------------------*
    Leslaw Bieniasz, Sep 20, 2004
    #1
    1. Advertising

  2. Leslaw Bieniasz wrote:
    > 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
    Victor Bazarov, Sep 20, 2004
    #2
    1. Advertising

  3. Cracow, 22.09.2004

    Hello,

    On Mon, 20 Sep 2004, Victor Bazarov wrote:

    > > 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: |
    *-------------------------------------------------------------------*
    | Interested in Computational Electrochemistry? |
    | Visit my web site: http://www.cyf-kr.edu.pl/~nbbienia |
    *-------------------------------------------------------------------*
    Leslaw Bieniasz, Sep 22, 2004
    #3
  4. Leslaw Bieniasz wrote:
    > [...]
    > 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
    Victor Bazarov, Sep 22, 2004
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. xiaohuamao

    Cyclic dependencies

    xiaohuamao, Aug 9, 2006, in forum: C++
    Replies:
    1
    Views:
    385
    Pierre Barbier de Reuille
    Aug 9, 2006
  2. Craig Sanders

    Cyclic dependencies and namespaces.

    Craig Sanders, Sep 5, 2007, in forum: C++
    Replies:
    1
    Views:
    397
    Glen Dayton
    Sep 5, 2007
  3. Replies:
    2
    Views:
    465
  4. Marcel Müller

    Smart pointer and cyclic dependencies

    Marcel Müller, Mar 21, 2008, in forum: C++
    Replies:
    1
    Views:
    608
    Marcel Müller
    Mar 22, 2008
  5. Marcel Müller
    Replies:
    0
    Views:
    494
    Marcel Müller
    Aug 8, 2009
Loading...

Share This Page