Reputation: 43
In an application I'm developing I have a template function like this:
template<class T>
void CIO::writeln(T item)
{
stringstream ss;
ss << item << '\r' << endl;
write(ss.str());
}
This function is called from several places, with T = const char* and T=std::string. With CodeSourcery Lite 2008.03-41 (GCC 4.3.2) this compiled and linked fine with -O3 compiler flag. However, since I changed to CodeSourcery Lite 2012.03-57 (GCC 4.6.3), compiling with -O3 is OK, but then linking fails with undefined reference to void CIO::writeln<std::string>(std::string)
. With -O2 or lower everything is OK, linking succeeds.
I had a deeper look into this and I discovered something strange in the assembly output: when compiling with -O2, I can find two specializations of the function: one for const char* (_ZN3CIO7writelnIPKcEEvT_
) and one for std::string (_ZN3CIO7writelnISsEEvT_
), but when compiling with -O3, the second specialization is missing, which explains the linking error.
Is this a compiler bug? Is this some weird optimization turned evil?
Thanks in advance!
Edit: this function is in a source file. Following Mike Seymour's comment, I moved it to the header and everything's fine now. I admit that I should've realized this earlier. Nevertheless, it still frightens me that a language rule is checked or not depending on an optimization flag.
Upvotes: 4
Views: 414
Reputation:
Unlike what the other answer says, this is probably not a compiler bug.
One of the optimisations that gets enabled by -O3
is function inlining. What I think is happening is:
Source file 1 is calling CIO::writeln
without having its definition available. It is compiled to object file 1.
Source file 2 is calling CIO::writeln
while having its definition available. It is compiled to object file 2.
Object file 1 will only be usable if object file 2 contains the definition of CIO::writeln
. If the call in source file 2 gets inlined, object file 2 won't contain a definition for it. If the call does not get inlined, a definition will be available.
The solution given in the comments, move the definition to a header file, is correct.
Upvotes: 1