Undefined Reference to Template Members

Undefined reference to template class constructor

This is a common question in C++ programming. There are two valid answers to this. There are advantages and disadvantages to both answers and your choice will depend on context. The common answer is to put all the implementation in the header file, but there's another approach will will be suitable in some cases. The choice is yours.

The code in a template is merely a 'pattern' known to the compiler. The compiler won't compile the constructors cola<float>::cola(...) and cola<string>::cola(...) until it is forced to do so. And we must ensure that this compilation happens for the constructors at least once in the entire compilation process, or we will get the 'undefined reference' error. (This applies to the other methods of cola<T> also.)

Understanding the problem

The problem is caused by the fact that main.cpp and cola.cpp will be compiled separately first. In main.cpp, the compiler will implicitly instantiate the template classes cola<float> and cola<string> because those particular instantiations are used in main.cpp. The bad news is that the implementations of those member functions are not in main.cpp, nor in any header file included in main.cpp, and therefore the compiler can't include complete versions of those functions in main.o. When compiling cola.cpp, the compiler won't compile those instantiations either, because there are no implicit or explicit instantiations of cola<float> or cola<string>. Remember, when compiling cola.cpp, the compiler has no clue which instantiations will be needed; and we can't expect it to compile for every type in order to ensure this problem never happens! (cola<int>, cola<char>, cola<ostream>, cola< cola<int> > ... and so on ...)

The two answers are:

  • Tell the compiler, at the end of cola.cpp, which particular template classes will be required, forcing it to compile cola<float> and cola<string>.
  • Put the implementation of the member functions in a header file that will be included every time any other 'translation unit' (such as main.cpp) uses the template class.

Answer 1: Explicitly instantiate the template, and its member definitions

At the end of cola.cpp, you should add lines explicitly instantiating all the relevant templates, such as

template class cola<float>;
template class cola<string>;

and you add the following two lines at the end of nodo_colaypila.cpp:

template class nodo_colaypila<float>;
template class nodo_colaypila<std :: string>;

This will ensure that, when the compiler is compiling cola.cpp that it will explicitly compile all the code for the cola<float> and cola<string> classes. Similarly, nodo_colaypila.cpp contains the implementations of the nodo_colaypila<...> classes.

In this approach, you should ensure that all the of the implementation is placed into one .cpp file (i.e. one translation unit) and that the explicit instantation is placed after the definition of all the functions (i.e. at the end of the file).

Answer 2: Copy the code into the relevant header file

The common answer is to move all the code from the implementation files cola.cpp and nodo_colaypila.cpp into cola.h and nodo_colaypila.h. In the long run, this is more flexible as it means you can use extra instantiations (e.g. cola<char>) without any more work. But it could mean the same functions are compiled many times, once in each translation unit. This is not a big problem, as the linker will correctly ignore the duplicate implementations. But it might slow down the compilation a little.

Summary

The default answer, used by the STL for example and in most of the code that any of us will write, is to put all the implementations in the header files. But in a more private project, you will have more knowledge and control of which particular template classes will be instantiated. In fact, this 'bug' might be seen as a feature, as it stops users of your code from accidentally using instantiations you have not tested for or planned for ("I know this works for cola<float> and cola<string>, if you want to use something else, tell me first and will can verify it works before enabling it.").

Finally, there are three other minor typos in the code in your question:

  • You are missing an #endif at the end of nodo_colaypila.h
  • in cola.h nodo_colaypila<T>* ult, pri; should be nodo_colaypila<T> *ult, *pri; - both are pointers.
  • nodo_colaypila.cpp: The default parameter should be in the header file nodo_colaypila.h, not in this implementation file.

Undefined reference to template member function

Templates need to only be defined within header files, this is why you are getting an undefined reference. I was able to run this successfully once I moved the source template code file into the header file.

Undefined reference to template members

Stack is a template. The complete definition has to go in its header file. That is, do not separate it into a .h and a .cpp file.

Undefined reference to specialized template member

template<class T>
struct A {};

template<class T>
struct B {
using type=T;
};

template<class T>
struct A<typename B<T>::type> {};

this is basically the same but with 1 fewer template layer.

This doesn't work either.

The problem is that B<T>::type or B<T>::template Z or whatever is, in the general case, an arbitrary compile-time function.

And in order to pattern match against it, we need to invert this arbitrary compile time function.

The standard says "compilers don't have to do that", which is one of the few sane things you can do here. It definitely says this for types; for templates, well, the standard's wording for template template parameters is often missing details, so I wouldn't be surprised if the wording was missing. But if it doesn't, it would be a bug in the standard.

In order to go from

template<class T>
struct A<typename B<T>::type> {};

to see if A<foo> matches it, it would have to test all types T to see which of them have a B<T>::type that equals foo.

This may not be what you intend to ask, but that is what you are asking for.

The same is true of your template example.

template <template <typename> class F>
struct A<B<F>::template C> {
static int foo();
};

you are asking for the compiler to check every type F such that if you pass it to the arbitrary template B<> then evaluated ::C in it, does the template match what you are passing A.

First fun case:

template<class X>
struct C0 {};
template <template <typename> class F>
struct B {
template <typename T>
using C=C0<X>:
};

now, what is F in A<C0>? Every single F qualifies.

template<class X>
struct C0 {};
template <template <typename> class F, class=void>
struct B {
template <typename T>
using C=C0<X>:
};
template<class X>
struct C1 {};
template <template <typename> class F, class=void>
struct B<
F,
std::enable_if_t<
proves_collatz_conjecture( F<int>::value )
>
> {
template <typename T>
using C=C1<T>;
};

now to pattern mach A<C0> the compiler must produce the F such that F<int>::value is a compile-time type that when passed to proves_collatz_conjecture returns true at compile time.

That would be useful.


template specialization is pattern matching. In C++ you cannot pattern match against dependent types (and presumably templates) as neither types nor templates have identity beyond their value.

You cannot inspect the scope that a variable, type or template is defined in. So you cannot pattern match that either.

If you want do do what you want, the template C has to itself have a property you can inspect and test against.

C++ undefined reference to template class method

Typically you want your template methods in the header, so they are compiled when needed. In case you really want to hide it in the implementation file, you have to explicitly instantiate the template in Graph.cpp like

template class  Graph<string>;

Since you have to do that for every type T you intend to use with Graph<T>, the point of the template class is somewhat defeated and you better put everything into the header

Undefined reference error for template method

Templated code implementation should never be in a .cpp file: your compiler has to see them at the same time as it sees the code that calls them (unless you use explicit instantiation to generate the templated object code, but even then .cpp is the wrong file type to use).

What you need to do is move the implementation to either the header file, or to a file such as VAConfig.t.hpp, and then #include "VAConfig.t.hpp" whenever you use any templated member functions.

undefined reference to template class member

Your template contains a declaration for Pairwise(K,V);, but it is never defined / implemented anywhere.

You need to add the definition in the same (or another) header file. To verify, replace the ; by {}, and the linker error should be gone: Pairwise(K,V) {} (it won't work but it will compile and link fine).

undefined reference to template function

The implementation of a non-specialized template must be visible to a translation unit that uses it.

The compiler must be able to see the implementation in order to generate code for all specializations in your code.

This can be achieved in two ways:

1) Move the implementation inside the header.

2) If you want to keep it separate, move it into a different header which you include in your original header:

util.h

namespace Util
{
template<class T>
QString convert2QString(T type , int digits=0);
}
#include "util_impl.h"

util_impl.h

namespace Util
{
template<class T>
QString convert2QString(T type, int digits=0)
{
using std::string;

string temp = (boost::format("%1") % type).str();

return QString::fromStdString(temp);
}
}

Undefined references to member functions of a class template

Template class methods must be defined in the header file. When you use a template class, the compiler actually compiles a version of that class for the given template parameters. Therefore, it is a requirement that the body of each method is available when including the header file.

Remove you source file and include the body in testclass.h:

template<typename T, typename container>
class TestClassX
{
public:
void gen(typename container::iterator first ) {

}
};


Related Topics



Leave a reply



Submit