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;
}
}
}
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
Re: Linking error, using template operator<<, undefined reference (NOT gen. link mist
Quote:
Originally Posted by
Paul McKenzie
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!