CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 3 of 3
  1. #1
    Join Date
    Apr 2008
    Posts
    12

    Linking error, using template operator<<, undefined reference (NOT gen. link mistake)

    **I know my mistake is in the code, not the g++ linking arguments, because g++ isn't complaining about the constructor or thisWorks() member function. Furthermore, commenting out main.cpp lines 10&11 (operator<< lines) makes it compile just fine.**

    Templates and I haven't gotten along well in the past, and I've been able to generally avoid them. I'm betting my error is something that will be semi-obvious to people who use templates semi-regularly.


    The code block for file "allInOne.cpp" compiles, and outputs:
    Code:
    HEADER
    Hello
    Hello, again
    The code block for files "main.cpp", "myLib.h", "myLib.cpp" fails compilation, giving:
    Code:
    main.cpp:10: undefined reference to `myLib::myOutput& myLib::operator<< <char [6]>(myLib::myOutput&, char const (&) [6])'
    main.cpp:11: undefined reference to `myLib::myOutput& myLib::operator<< <char [13]>(myLib::myOutput&, char const (&) [13])'

    (Note: I am aware that using my object by reference or pointer sliced to an ostream will break my invariant, and that I need to re-do my design. superbonzo pointed this out to me at http://forums.codeguru.com/showthrea...40#post2066940 )


    So, this works fine:
    Code:
    ########## FILE allInOne.cpp ##########
    
    #include <iostream>
    using namespace std;
    
    
    
    namespace myLib {
    
    class myOutput : public std::ostream {
       public:
          myOutput();
          void thisWorks();
          template <typename T>
          friend myOutput& operator<<(myOutput& myo, const T& v);
       private:
          void displayHeader();
          bool displayedHeader;
    };
    
    myOutput::myOutput() : ostream(cout.rdbuf()), displayedHeader(false) {
    }
    
    void myOutput::thisWorks() {
    }
    
    template <typename T>
    myOutput& operator<<(myOutput& myo, const T& v) {
       myo.displayHeader();
       static_cast<std::ostream&>(myo) << v;
       return myo;
    }
    
    void myOutput::displayHeader() {
       if(false == displayedHeader) {
          static_cast<ostream&>(*this) << "HEADER" << endl;
          displayedHeader = true;
       }
    }
    
    }
    
    using namespace myLib;
    
    
    
    int main() {
       myOutput output;
       output.thisWorks();
       output << "Hello" << endl;
       output << "Hello, again" << endl;
    }
    Moving this into a library is when it gives compilation errors...
    Code:
    ########## FILE main.cpp ##########
    
    #include <myLib.h>
    using namespace myLib;
    
    #include <iostream>
    using namespace std;
    
    int main() {
       myOutput output;
       output.thisWorks();
       output << "Hello" << endl;
       output << "Hello, again" << endl;
    }
    Code:
    ########## FILE myLib.h ##########
    
    #ifndef __MYLIB__
    #define __MYLIB__
    
    #include <iostream>
    
    namespace myLib {
    
    class myOutput : public std::ostream {
       public:
          myOutput();
          void thisWorks();
          template <typename T>
          friend myOutput& operator<<(myOutput& myo, const T& v);
       private:
          void displayHeader();
          bool displayedHeader;
    };
    
    }
    
    #endif
    Code:
    ########## FILE myLib.cpp ##########
    
    #include <myLib.h>
    using namespace myLib;
    
    using namespace std;
    
    namespace myLib {
    
    myOutput::myOutput() : ostream(cout.rdbuf()), displayedHeader(false) {
    }
    
    void myOutput::thisWorks() {
    }
    
    template <typename T>
    myOutput& operator<<(myOutput& myo, const T& v) {
       myo.displayHeader();
       static_cast<std::ostream&>(myo) << v;
       return myo;
    }
    
    void myOutput::displayHeader() {
       if(false == displayedHeader) {
          static_cast<ostream&>(*this) << "HEADER" << endl;
          displayedHeader = true;
       }
    }
    
    }

  2. #2
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Linking error, using template operator<<, undefined reference (NOT gen. link mist

    Quite simply, template declaration and implementation should be together, and not in separate compilation units. For an example, look at the <vector> header -- you will see declaration and implementation in the same file. The reason is that template is compile-time code. Therefore the compiler must have the full template code when you instantiate a template.

    If you don't do things that way, then the other solution is to create a "dummy" module, include all the template code, and then instantiate any and every way you will use the template. You compile this dummy module, feed it to the linker, and the linker will then see all of your instantiations. The disadvantage of this is that you need to know and to keep track of all of the various instantiations in your program. IMO, this is too much of a headache, especially if the templates are complex in nature.

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; May 20th, 2012 at 09:25 PM.

  3. #3
    Join Date
    Apr 2008
    Posts
    12

    Re: Linking error, using template operator<<, undefined reference (NOT gen. link mist

    Quote Originally Posted by Paul McKenzie View Post
    Quite simply, template declaration and implementation should be together, and not in separate compilation units. For an example, look at the <vector> header -- you will see declaration and implementation in the same file. The reason is that template is compile-time code. Therefore the compiler must have the full template code when you instantiate a template.

    If you don't do things that way, then the other solution is to create a "dummy" module, include all the template code, and then instantiate any and every way you will use the template. You compile this dummy module, feed it to the linker, and the linker will then see all of your instantiations. The disadvantage of this is that you need to know and to keep track of all of the various instantiations in your program. IMO, this is too much of a headache, especially if the templates are complex in nature.

    Regards,

    Paul McKenzie
    Thanks, dead on!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured