Base template class symbols failing to link.

Discussion in 'C++' started by willo@cynd.net, May 22, 2009.

  1. Guest

    All,

    I'm having problems getting base-class template symbols to link
    correctly.

    My unit-test files are included below. I defined a templated Base-
    Class 'A', and a templated Derived-Class 'B', only defining the
    constructor and destructor.

    I'm using 'g++-4.2', and get errors like:
    willo:~/tmp$ g++ main.o B.o A.o -o main
    B.o: In function `B<int>::B()':
    B.cpp:(.text._ZN1BIiEC1Ev[B<int>::B()]+0x11): undefined reference to
    `A<int>::A()'
    B.o: In function `B<int>::~B()':
    B.cpp:(.text._ZN1BIiED1Ev[B<int>::~B()]+0x11): undefined reference to
    `A<int>::~A()'

    This is despite the fact that I'm linking in another object file that
    defines these symbols:
    willo:~/tmp/$ nm --demangle A.o
    0000000000000000 t instantiate_templated_class()
    0000000000000000 W A<int>::A()
    0000000000000000 W A<int>::~A()
    U __gxx_personality_v0

    Interestingly, if I remove the template parameter from Class A and B,
    this error does not occur.

    So, my question is, what am I doing wrong, or is what I'm trying to do
    possible?

    -- Charles Wilcox

    willo:~/tmp$ cat A.h
    #ifndef A_HEADER
    #define A_HEADER

    template< typename T >
    class A
    {
    public: // methods
    A();

    ~A();
    };

    #endif // ifndef A_HEADER

    willo:~/tmp$ cat A.cpp
    #include "A.h"

    template< typename T >
    A< T >::A() {}

    template< typename T >
    A< T >::~A() {}

    static void instantiate_templated_class()
    {
    A< int > a;
    }

    willo:~/tmp$ cat B.h
    #ifndef B_HEADER
    #define B_HEADER

    #include "A.h"

    template< typename T >
    class B : public A< T >
    {
    public: // methods
    B();

    ~B();
    };

    #endif // ifndef B_HEADER

    willo:~/tmp$ cat B.cpp
    #include "B.h"

    template< typename T >
    B< T >::B() {}

    template< typename T >
    B< T >::~B() {}

    static void instantiate_templated_class()
    {
    B< int > b;
    }

    willo:~/tmp$ cat main.cpp
    #include "B.h"

    int main( int argc, char* argv )
    {
    B< int > b;

    return 0;
    }
     
    , May 22, 2009
    #1
    1. Advertising

  2. Leclerc Guest

    Leclerc, May 22, 2009
    #2
    1. Advertising

  3. Guest

    On May 22, 1:17 am, Leclerc <> wrote:
    > http://www.parashift.com/c -faq-lite/templates.html
    >
    > read about linking errors, separating templates into headers-sources,
    > and the rest of course :)


    Leclerc,

    I've reviewed the Parashift info regarding templates and header / body
    separation, and none of the information helps.

    To re-iterate, I'm compiling each .cpp file just fine. I believe I've
    separated the the .h and .cpp parts correctly.

    This guide says nothing about linking templated base / derived
    classes.

    It's linking that has the problem. This is unexpected, as one of the
    input compilation unit's defines the symbols that it complains about
    not finding.

    willo:~/tmp$ make
    g++ -c -o main.o main.cpp
    g++ -c -o B.o B.cpp
    g++ -c -o A.o A.cpp
    g++ main.o B.o A.o -o main
    B.o: In function `B<int>::B()':
    B.cpp:(.text._ZN1BIiEC1Ev[B<int>::B()]+0x11): undefined reference to
    `A<int>::A()'
    B.o: In function `B<int>::~B()':
    B.cpp:(.text._ZN1BIiED1Ev[B<int>::~B()]+0x11): undefined reference to
    `A<int>::~A()'
    collect2: ld returned 1 exit status
    make: *** [main] Error 1
    willo:~/tmp/$ nm --demangle A.o
    0000000000000000 t instantiate_templated_class()
    0000000000000000 W A<int>::A()
    0000000000000000 W A<int>::~A()
    U __gxx_personality_v0
    willo:~/tmp/$ nm --demangle B.o
    0000000000000000 t instantiate_templated_class()
    U A<int>::A()
    U A<int>::~A()
    0000000000000000 W B<int>::B()
    0000000000000000 W B<int>::~B()
    U __gxx_personality_v0

    What is preventing the symbols for A in A.o from being used at link
    time?

    I could instantiate the A<int> symbols in B.o, but then I'd have
    duplicate symbols, which can cause other linking errors in future
    usage.

    -- Charles Wilcox
     
    , May 22, 2009
    #3
  4. Noah Roberts Guest

    wrote:
    > On May 22, 1:17 am, Leclerc <> wrote:
    >> http://www.parashift.com/c -faq-lite/templates.html
    >>
    >> read about linking errors, separating templates into headers-sources,
    >> and the rest of course :)

    >
    > Leclerc,
    >
    > I've reviewed the Parashift info regarding templates and header / body
    > separation, and none of the information helps.
    >
    > To re-iterate, I'm compiling each .cpp file just fine. I believe I've
    > separated the the .h and .cpp parts correctly.


    You haven't. You've not given the compiler the information it needs to
    instantiate the template's functions in B.cpp and main.cpp. Move your
    template's function definitions to the header file and get rid of both
    A.cpp and B.cpp completely.
    >
    > This guide says nothing about linking templated base / derived
    > classes.
    >
    > It's linking that has the problem. This is unexpected, as one of the
    > input compilation unit's defines the symbols that it complains about
    > not finding.


    Of course it's linking that's the problem.

    > I could instantiate the A<int> symbols in B.o, but then I'd have
    > duplicate symbols, which can cause other linking errors in future
    > usage.


    B.o has no knowledge of there being an instantiation of A<int> anyway.
    It's going to try to build its own and since you've not given it the
    necessary knowledge to do so, it won't be able to.
     
    Noah Roberts, May 22, 2009
    #4
  5. Guest

    On May 22, 1:35 pm, (blargg) wrote:
    > willo wrote:
    > > On May 22, 1:17=A0am, Leclerc <> wrote:
    > > >http://www.parashift.com/c -faq-lite/templates.html

    >
    > > > read about linking errors, separating templates into headers-sources,
    > > > and the rest of course :)

    >
    > > I've reviewed the Parashift info regarding templates and header / body
    > > separation, and none of the information helps.

    >
    > > To re-iterate, I'm compiling each .cpp file just fine.  I believe I've
    > > separated the the .h and .cpp parts correctly.

    >
    > Try re-reading questions 35.12 and 35.13, as they directly address your problem:
    >
    > http://www.parashift.com/c -faq-lite/templates.html#faq-35.12


    I just got help from Marshall, and have resolved this.

    Actually, section 35.13 has the answer, although the example is only
    for a template-function.

    In my posted sample-code, I used a static function
    "instantiate_templated_class" per .cpp file to instantiate the
    templated versions I wanted, specifically A< int > in A.cpp and B< int
    > in B.cpp. I expected this to create the symbols needed in other

    compilation-units.

    However, that didn't work, and is not the way to do it. I should have
    done:
    template class A< int >
    in A.cpp and:
    template class B< int >
    in B.cpp.

    I had tried to do this before my posting, but I must have gotten the
    syntax incorrect.

    Anyway, thanks to all here and Marshall Cline for directing me to the
    solution.

    -- Charles Wilcox
     
    , May 22, 2009
    #5
    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. Matt Graham
    Replies:
    0
    Views:
    578
    Matt Graham
    Jul 21, 2003
  2. Tim Clacy
    Replies:
    12
    Views:
    631
    Dan W.
    Dec 3, 2003
  3. Replies:
    2
    Views:
    591
  4. nguillot
    Replies:
    5
    Views:
    561
  5. Hicham Mouline
    Replies:
    1
    Views:
    626
    Victor Bazarov
    Apr 20, 2009
Loading...

Share This Page