views:

388

answers:

2

I converted a function to a template, and started getting this error. I must not be understanding a limitation of templates. Can someone tell me why this is broken?

I am receiving this error:

Undefined symbols:
  "bool foo<int>(int const&, int const&)", referenced from:
      _main in file1.o
ld: symbol(s) not found

When I link the following code. The code is simplified, but still fails. The first file contains:

#include <iostream>
template <class T> bool foo (const T&, const T&);

int main ()
{
  int left = 1;
  int right = 2;

  if (foo <int> (left, right))
    std::cout << "foo!" << std::endl;

  return 0;
}

And the second file contains:

template <class T> bool foo (const T& left, const T& right)
{
  return true;
}
+1  A: 

It's been years since I did much C++, but I think you are encountering a problem of separate compilation. Templates are instantiated at compilation, not linking.

Therefore, when you are making the call to foo(), you are not really instantiating the template in the sense that no new function code is generated, you're just creating a symbol that the linker has to resolve.

However, when the second file is compiled, it has just the template and it is never instantiated, so no version of foo() that actually deals with ints is generated. As a result, when you link everything together, you get the error.

I'm not 100% sure what to do about this, but I suspect that you would need to force an instantiation of foo() with ints in that second file (assuming it's a C++). I only worked with class templates, not function templates, I'm sure someone here will give you the exact code in a few...

Uri
+2  A: 

For the reason Uri gave, template methods are usually defined in the header file. Because yours is a function and not a method of a class, explicitly define it (in the header file which may be included by more than one CPP file) as static or inline.

Put this in your foo.h

template<class T> inline bool foo (const T& left, const T& right)
{
  return true;
}

Put this in your main.cpp

#include <iostream>
#include "foo.h"

int main ()
{
  int left = 1;
  int right = 2;

  if (foo <int> (left, right))
    std::cout << "foo!" << std::endl;

  return 0;
}

The cpp code now sees the whole declaration of the template function.

Other solutions are listed here: How can I avoid linker errors with my template functions?

ChrisW
static/inline mods don't have any effect. I'm stumped.
Paul Beckingham
I added an example and a hyperlink to my answer.
ChrisW
Thanks for the link, I see the correct syntax is something like template foo<int>(...); I didn't remember the exact syntax for doing this without the horrible inline-in-an-h file.
Uri