2

I'm trying to move an explicit specialization of a template member function to a .cpp file, but the linker keeps saying "unresolved external symbol".

Foo.hpp

struct Color {};

class Foo
{
public:
  template<typename T> int add(T b);
  template<> int add(Color b);
};

template<typename T>
int Foo::add(T b)
{
  return 0;
}

Foo.cpp

#include "Foo.hpp"

template<>
int Foo::add(Color b)
{
  return 0;
}
template int Foo::add(Color b);

Bar.cpp

#include "Foo.hpp"

void f() {
  Foo dbg;
  dbg.add(5);
  dbg.add(Color());
}

I tried to explicitly instantiate the member function in Foo.cpp. Why doesn't this have any effect?

I'm aware of two solutions: I could move the definition of int Foo::add(Color) into the .hpp, and mark it inline. Or I could force the instantiation in Foo.cpp like this:

void dummy() {
  Foo().add(Color());
}

How come I can't use template int Foo::add(Color b) to instantiate the function? Am I using the wrong syntax?

Andreas Haferburg
  • 5,189
  • 3
  • 37
  • 63
  • 2
    Just create a function overload without function template specialization i.e. `int add(Color)`. – aep Feb 21 '20 at 11:53
  • @aep Yes, that works, thank you. But. Why. I'm confused. What's the point of explicit full specialization, then? – Andreas Haferburg Feb 21 '20 at 11:57
  • Well function specialisation & overloading are different from the compiler point of view. I don't want to go into details, but follow https://stackoverflow.com/questions/7108033/template-specialization-vs-function-overloading. – aep Feb 21 '20 at 12:04
  • 1
    I must admit I stumbled over the same syntax issue like you. With the help of answer, I got the [**sample**](http://coliru.stacked-crooked.com/a/eef3cb6f3983b0b0) running. And, yes, you were right. Template specializations can be in a translation unit. (There is only one possible implementation which the linker can pick up.) My fault... :-( (but, hey, I learned something.) :-) – Scheff's Cat Feb 21 '20 at 12:16
  • 1
    @Scheff All good. If you could learn something from my ignorance then SO fulfills its purpose. :) – Andreas Haferburg Feb 21 '20 at 12:36

1 Answers1

6

I'm not sure, but I think you're trying to do this.

In Foo.h

struct Color {};

class Foo
{
public:
    template<typename T> int add(T b);
};

// declare, but do not implement, specialization
template<>
int Foo::add<Color>(Color c);

// general implementation
template<typename T>
int Foo::add(T b)
{
    return 0;
}

In Foo.cpp

#include "Foo.h"

// explicitly implement
template<>
int Foo::add<Color>(Color b)
{
    return 42;
}

Finally, main.cpp

#include "Foo.h"

int main()
{
    Foo f;
    std::cout << f.add(Color()) << '\n';
}

Output

42
WhozCraig
  • 65,258
  • 11
  • 75
  • 141