errors = templates * friends;

Discussion in 'C++' started by fabio de francesco, Jun 24, 2004.

  1. Hello,

    I'm just joking with the Subject, but I really don't know how to make
    a synthesis of two questions about some code I'm trying to write.

    In the following I post this little code, with "..." meaning what I
    think can be omitted for brevity.


    // file database.h
    ....
    template <typename T>
    class DataBase
    {
    public:
    DataBase();
    ...
    private:
    ...
    void run();
    ostream& print( ostream & );
    friend ostream& operator<<(ostream &out, DataBase<T> &db)
    { return db.print( out ); }
    };
    ....

    // file database.cpp
    ....
    template <typename T>
    DataBase<T>::DataBase()
    {...}
    template<typename T>
    void DataBase<T>::run()
    {...}
    ....

    // file usedb.cpp
    ....
    #include "database.h"
    #include "person.h"
    ....
    int main()
    {
    DataBase<Person> db; // usedb.cpp:11 (error)
    ...
    return 0;
    }

    The first problem is that the linker editor ( I suppose ) comes out
    with this error:

    /database/src/usedb.cpp:11: undefined reference to
    `DataBase<Person>::DataBase[in-charge]()'

    I got the same error also if I try to instantiate 'DataBase<int> db'.

    This is not the first time I use templates but I've never seen such an
    error.
    I'm sure I am doing some stupid thing.

    The second problem arises if I try to extract the implementation code
    of the friend overloaded operator "<<" from the class definition (
    database.h ) to be put in the implementation file ( database.cpp ).

    // file DataBase.h
    ....
    friend ostream& operator<<( ostream &out, DataBase<T> &db );
    ....

    // file DataBase.cpp
    ....
    template<typename T>
    ostream& operator<<( ostream &out, DataBase<T> &db )
    { return db.print( out ); }
    ....

    Here the errors, while compiling:

    /src/database.h:31: warning: friend declaration `std::eek:stream&
    operator<<(std::eek:stream&, DataBase<T>&)' declares a non-template
    function
    /src/database.h:31: warning: (if this is not what you intended, make
    sure the function template has already been declared and add <> after
    the function name here) -Wno-non-template-friend disables this warning

    That's all. I want to thank in advance everyone who will explain what
    kind of errors I put in the code. I would appreciate also any partial
    reply on the first topic that is the most important for me.

    Ciao,

    Fabio De Francesco.
     
    fabio de francesco, Jun 24, 2004
    #1
    1. Advertising

  2. fabio de francesco wrote in
    news: in comp.lang.c++:

    > Hello,
    >
    > I'm just joking with the Subject, but I really don't know how to make
    > a synthesis of two questions about some code I'm trying to write.
    >
    > In the following I post this little code, with "..." meaning what I
    > think can be omitted for brevity.
    >
    >
    > // file database.h
    > ...
    > template <typename T>
    > class DataBase
    > {
    > public:
    > DataBase();
    > ...
    > private:
    > ...
    > void run();
    > ostream& print( ostream & );


    This is a non-template function, you can't define it outside of the
    class-template, as you try to do later.

    > friend ostream& operator<<(ostream &out, DataBase<T> &db)
    > { return db.print( out ); }
    > };
    > ...
    >


    Here's your first problem, templates need to be defined in the
    the same compilation that uses them, put these defenition's in
    your header file.

    > // file database.cpp
    > ...
    > template <typename T>
    > DataBase<T>::DataBase()
    > {...}
    > template<typename T>
    > void DataBase<T>::run()
    > {...}
    > ...

    [snip]

    Here's an example of a template friend (note all the cruft):

    #include <iostream>
    #include <ostream>


    /* Forward declare X, so we can forward declare operator <<
    */
    template < typename T > struct X;
    template < typename T >
    std::eek:stream & operator << ( std::eek:stream &os, X< T > const & );


    template < typename T >
    struct X
    {
    friend /* Note the <> */
    std::eek:stream & operator << <>( std::eek:stream &os, X< T > const & );
    };

    /* declaration/defenition - in the *header*
    */
    template < typename T >
    std::eek:stream & operator << ( std::eek:stream &os, X< T > const & )
    {
    os << "friend\n";
    return os;
    }

    int main()
    {
    X< int > x;
    std::cout << x;
    }

    Alternativly do it like this:

    #include <iostream>
    #include <ostream>

    template < typename T >
    struct X
    {
    private:
    void printon( std::eek:stream &os ) const;
    friend std::eek:stream & operator << ( std::eek:stream &os, X< T > const &x )
    {
    x.printon( os );
    return os;
    }
    };


    template < typename T >
    void X< T >::printon( std::eek:stream &os ) const
    {
    os << "friend\n";
    }

    int main()
    {
    X< int > x;
    std::cout << x;
    }

    Slightly less cruft :).

    Rob.
    --
    http://www.victim-prime.dsl.pipex.com/
     
    Rob Williscroft, Jun 24, 2004
    #2
    1. Advertising

  3. >
    > Here's an example of a template friend (note all the cruft):
    >
    > #include <iostream>
    > #include <ostream>
    >
    >
    > /* Forward declare X, so we can forward declare operator <<
    > */
    > template < typename T > struct X;
    > template < typename T >
    > std::eek:stream & operator << ( std::eek:stream &os, X< T > const & );
    >


    This confuses me, I know what to do but I still don't understand why.

    Why is it necessary to forward declare the operator in this case?

    john
     
    John Harrison, Jun 24, 2004
    #3
  4. John Harrison wrote in news: in
    comp.lang.c++:

    >>
    >> Here's an example of a template friend (note all the cruft):
    >>
    >> #include <iostream>
    >> #include <ostream>
    >>
    >>
    >> /* Forward declare X, so we can forward declare operator <<
    >> */
    >> template < typename T > struct X;
    >> template < typename T >
    >> std::eek:stream & operator << ( std::eek:stream &os, X< T > const & );
    >>

    >
    > This confuses me, I know what to do but I still don't understand why.
    >
    > Why is it necessary to forward declare the operator in this case?
    >


    Because the friend /statement/ in this:

    template < typename T >
    struct X
    {
    friend /* Note the <> */
    std::eek:stream & operator << <>( std::eek:stream &os, X< T > const & );
    };

    isn't a declaration.

    The following example contains a declaration but its to generic, i.e. it
    grants friendship to widely, not that that is ever a /real/ problem.

    #include <iostream>
    #include <ostream>

    template < typename T >
    struct Y
    {
    template < typename U >
    friend
    std::eek:stream &operator << ( std::eek:stream &os, Y< U > const & );

    };

    template < typename T >
    std::eek:stream & operator <<( std::eek:stream &os, Y< T > const & )
    {
    os << "friend\n";
    return os;
    }

    int main()
    {
    Y< int > y;
    std::cout << y;
    }

    Rob.
    --
    http://www.victim-prime.dsl.pipex.com/
     
    Rob Williscroft, Jun 24, 2004
    #4
  5. "Rob Williscroft" <> wrote in message
    news:Xns9512F14004C35ukcoREMOVEfreenetrtw@130.133.1.4...
    > John Harrison wrote in news: in
    > comp.lang.c++:
    >
    > >>
    > >> Here's an example of a template friend (note all the cruft):
    > >>
    > >> #include <iostream>
    > >> #include <ostream>
    > >>
    > >>
    > >> /* Forward declare X, so we can forward declare operator <<
    > >> */
    > >> template < typename T > struct X;
    > >> template < typename T >
    > >> std::eek:stream & operator << ( std::eek:stream &os, X< T > const & );
    > >>

    > >
    > > This confuses me, I know what to do but I still don't understand why.
    > >
    > > Why is it necessary to forward declare the operator in this case?
    > >

    >
    > Because the friend /statement/ in this:
    >
    > template < typename T >
    > struct X
    > {
    > friend /* Note the <> */
    > std::eek:stream & operator << <>( std::eek:stream &os, X< T > const & );
    > };
    >
    > isn't a declaration.


    I think I'd quibble with your terminology. I guess (if I understand you
    right) that I'd say although the above does declare friendship it doesn't
    declare the function template itself. Which thinking about it seems
    reasonable enough, it doesn't look anything like a function template
    declaration.

    Thanks, John
     
    John Harrison, Jun 25, 2004
    #5
  6. Rob Williscroft <> wrote in message news:<Xns9512C87955018ukcoREMOVEfreenetrtw@130.133.1.4>...

    > Here's your first problem, templates need to be defined in the
    > the same compilation that uses them, put these defenition's in
    > your header file.
    >
    > > // file database.cpp
    > > ...
    > > template <typename T>
    > > DataBase<T>::DataBase()
    > > {...}
    > > template<typename T>
    > > void DataBase<T>::run()
    > > {...}
    > > ...

    > [snip]

    ....
    > /* Forward declare X, so we can forward declare operator <<
    > */
    > template < typename T > struct X;
    > template < typename T >
    > std::eek:stream & operator << ( std::eek:stream &os, X< T > const & );
    >
    >
    > template < typename T >
    > struct X
    > {
    > friend /* Note the <> */
    > std::eek:stream & operator << <>( std::eek:stream &os, X< T > const & );
    > };
    >
    > /* declaration/defenition - in the *header*
    > */
    > template < typename T >
    > std::eek:stream & operator << ( std::eek:stream &os, X< T > const & )
    > {
    > os << "friend\n";
    > return os;
    > }
    >
    > int main()
    > {
    > X< int > x;
    > std::cout << x;
    > }


    Thank you Rob.

    I actually solved the problem by using the forward declarations plus
    the "<>" notation as you wrote, but fortunately I wasn't to much
    inclined to put the definitions of the functions ( that are a thousand
    of lines of code ) into the header file.

    With this is my mind I found a way to keep untouched the code in
    database.cpp by adding pre-declarations of the possible use of
    template parameters ( I'm not sure I can name them this way ),

    So I added ( in database.cpp ):

    #include "person.h"
    template DataBase<Person>;

    #include "myfriends"
    template DataBase<MyFriends>;

    and so on. Now I can ( in usedb.cpp ) instantiate

    DataBase<Person> dbPerson;
    DataBase<MyFriends> dbMyFriends;

    with no more linker editor errors.

    Your advice was enough to make me put that friend function
    implementation in database.cpp too, without any further modification.

    Ciao,
    Fabio De Francesco.
     
    fabio de francesco, Jun 25, 2004
    #6
  7. "fabio de francesco" <> schreef in bericht
    news:...
    > Hello,
    >
    > I'm just joking with the Subject, but I really don't know how to make
    > a synthesis of two questions about some code I'm trying to write.
    >
    > In the following I post this little code, with "..." meaning what I
    > think can be omitted for brevity.
    >
    >
    > // file database.h
    > ...
    > template <typename T>
    > class DataBase
    > {
    > public:
    > DataBase();
    > ...
    > private:
    > ...
    > void run();
    > ostream& print( ostream & );
    > friend ostream& operator<<(ostream &out, DataBase<T> &db)
    > { return db.print( out ); }
    > };
    > ...
    >
    > // file database.cpp
    > ...
    > template <typename T>
    > DataBase<T>::DataBase()
    > {...}
    > template<typename T>
    > void DataBase<T>::run()
    > {...}
    > ...
    >
    > // file usedb.cpp
    > ...
    > #include "database.h"
    > #include "person.h"
    > ...
    > int main()
    > {
    > DataBase<Person> db; // usedb.cpp:11 (error)
    > ...
    > return 0;
    > }
    >
    > The first problem is that the linker editor ( I suppose ) comes out
    > with this error:
    >
    > /database/src/usedb.cpp:11: undefined reference to
    > `DataBase<Person>::DataBase[in-charge]()'
    >
    > I got the same error also if I try to instantiate 'DataBase<int> db'.
    >
    > This is not the first time I use templates but I've never seen such an
    > error.
    > I'm sure I am doing some stupid thing.
    >
    > The second problem arises if I try to extract the implementation code
    > of the friend overloaded operator "<<" from the class definition (
    > database.h ) to be put in the implementation file ( database.cpp ).
    >
    > // file DataBase.h
    > ...
    > friend ostream& operator<<( ostream &out, DataBase<T> &db );
    > ...
    >
    > // file DataBase.cpp
    > ...
    > template<typename T>
    > ostream& operator<<( ostream &out, DataBase<T> &db )
    > { return db.print( out ); }
    > ...
    >
    > Here the errors, while compiling:
    >
    > /src/database.h:31: warning: friend declaration `std::eek:stream&
    > operator<<(std::eek:stream&, DataBase<T>&)' declares a non-template
    > function
    > /src/database.h:31: warning: (if this is not what you intended, make
    > sure the function template has already been declared and add <> after
    > the function name here) -Wno-non-template-friend disables this warning
    >
    > That's all. I want to thank in advance everyone who will explain what
    > kind of errors I put in the code. I would appreciate also any partial
    > reply on the first topic that is the most important for me.
    >
    > Ciao,
    >
    > Fabio De Francesco.



    Templates that will be used in multiple files have to be implemented in the
    header file.
    That's all, I think.
     
    Wouter Lievens, Jun 27, 2004
    #7
  8. "Wouter Lievens" <> wrote in message news:<40de923c$0$9540$>...

    > Templates that will be used in multiple files have to be implemented in the
    > header file.
    > That's all, I think.


    I think, with all respect, you'd better read all the thread, in which
    more solutions have been found, before stating something that has been
    outdone a few days ago (without implementing templates in the header
    file).

    I don't want to be polemical, it is just that someone can rely on what
    is added at the end of a thread by thinking that some steps forward
    have been taken after days of discussion.

    Regards,

    Fabio De Francesco
     
    fabio de francesco, Jun 28, 2004
    #8
    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. Kevin Christopher

    templates and friends

    Kevin Christopher, Jul 1, 2003, in forum: C++
    Replies:
    3
    Views:
    359
    tom_usenet
    Jul 2, 2003
  2. JKop
    Replies:
    3
    Views:
    523
  3. Replies:
    2
    Views:
    617
  4. recover
    Replies:
    2
    Views:
    859
    recover
    Jul 25, 2006
  5. Replies:
    0
    Views:
    683
Loading...

Share This Page