Reputation: 41444
I have a Visual Studio 2012 project equivalent to this:
Header.h
template< class T >
inline int Demonstrate( const char *txt, T *input )
{
return printf("%s %d %f\n", txt, input->Integer(), input->Real() );
}
Source.cpp
#include "Header.h"
class Foo
{
public:
int Integer() { return 2; }
float Real() { return 3.14159f; }
};
int main()
{
Foo example;
printf( "%d\n", Demonstrate( "foo:", &example ) );
return 0;
}
Yet when I compile I receive a LNK2019 error:
unresolved external symbol "int __cdecl Demonstrate(char const *,class Foo *)"
Ordinarily this occurs when a templated function is declared in a header but only defined in a cpp, but that is not the case here. The function is defined inline in the header.
What could cause this and how can I fix it?
edit
This happens even if I remove the header altogether and just stick Demonstrate() at the top of Source.cpp. It happens whether "Inline Function Expansion" in the project properties is set to "Default" or to "/Ob2"
. This must be some project settings thing, but what?
Upvotes: 3
Views: 701
Reputation: 41444
So I tracked this down and it turns out that Joel was on the right path. The function Demonstrate() had been prototyped multiple times in multiple headers — in a very nonobvious way. There was the explicit int Demonstrate( const char *txt, Foo *input )
declaration, which is what I replaced with a template.
But there were several other headers that had, strewn across them, something analogous to this (you can infer that the actual function and class names were much more complicated):
header a.h:
#define FUNC_PREFIX Demo
header b.h:
#define REGISTER_CLASS( retype, classname, FUNC_SUFFIX ) retype FUNC_PREFIX ## FUNC_SUFFIX ( const char *txt, classname *ptr )
header c.h:
REGISTER_CLASS( int, Foo, nstrate );
REGISTER_CLASS( int, Bar, nstrate );
// etc
I'm not sure what to draw from this. On the one hand it's a very specific bug to a very specific codebase and too localized to be a useful SO question. On the other hand, there is a teachable moment here:
DON'T USE MACROS TO DEFINE GLOBAL FUNCTIONS IN SNEAKY WAYS.
Or else poor saps like me will spend hours tracking down problems like this.
Upvotes: 2
Reputation: 63481
Sometimes you can't rely on automatic template specialization. I've encountered this before with VS and ended up having to be explicit. ie
Demonstrate<Foo>("foo:", &example)
Upvotes: 1