Undefined reference to partial specialized templat

2019-08-19 20:49发布

问题:

So I had an problem with partial specialization of function templates. I choose the solution described here: Question

Now I have this:

#include <vector>
#include <iostream>

template <typename T> struct helper {
    static void print(T value) { std::cout << value; }
};
template <typename T> struct helper<std::vector<T>> {
    static void print(std::vector<T> const &value) { }
};

template <typename T>
void print (T const &value) {
    // Just delegate.
    helper<T>::print (value);
}


int main () {
    print (5);
    std::vector<int> v;
    print (v);
}

But I want to have this layout:

helper.hpp

#include <vector>
#include <iostream>

template <typename T> struct helper {
    static void print(T value) { std::cout << value; }
};

vector_helper.cpp

#include <vector>
#include <iostream>

template <typename T> struct helper<std::vector<T>> {
    static void print(std::vector<T> const &value) { }
};

print.hpp

#include "helper.hpp"

template <typename T>
void print (T const &value) {
    // Just delegate.
    helper<T>::print (value);
}

main.cpp

#include "print.hpp"

int main () {
    print (5);
    std::vector<int> v;
    print (v);
}

Compiled like this:

g++ main.cpp vector_helper.cpp

The problem is that MinGW is producing linking-time erros: undefined reference to helper<vector<...>>::print(vector<...>)

When I add the line:

#include "vector_helper.cpp"

before int main() {...}, it compiles fine and also works. How can I solve it, because I want to add the class specialization in the file linked by the g++ command.

回答1:

Those template classes can't be split into separate object files and remain wholly unspecialised. If you look at the standard templates like vector, you'll see that everything is in a single headerfile for this reason.

If you want to hide the implementation of your templates like that, you have to force instantiation of them to one or more specific types. You might do this by sticking something like

template class helper<std::vector<int>>;

at the end of vector_helper.cpp, if I recall correctly. But you're best off keeping all your templates in headers.