**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:
The code block for files "main.cpp", "myLib.h", "myLib.cpp" fails compilation, giving:Code:HEADER Hello Hello, again
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:
Moving this into a library is when it gives compilation errors...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; }
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; }; } #endifCode:########## 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; } } }




Reply With Quote