119

When I write C++ code for a class using templates and split the code between a source (CPP) file and a header (H) file, I get a whole lot of "unresolved external symbol" errors when it comes to linking the final executible, despite the object file being correctly built and included in the linking. What's happening here, and how can I fix it?

dlanod
  • 8,664
  • 8
  • 54
  • 96
  • See also http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file – sth Sep 07 '13 at 01:41

3 Answers3

143

Templated classes and functions are not instantiated until they are used, typically in a separate .cpp file (e.g. the program source). When the template is used, the compiler needs the full code for that function to be able to build the correct function with the appropriate type. However, in this case the code for that function is detailed in the template's source file and hence unavailable.

As a result of all this the compiler just assumes that it's defined elsewhere and only inserts the call to the templated function. When it comes to compile the template's source file, the specific template type that is being used in the program source isn't used there so it still won't generate the code required for the function. This results in the unresolved external symbol.

The solutions available for this are to:

  1. include the full definition of the member function in the template's header file and not have a source file for the template,
  2. define all the member functions in the template's source file as "inline" (Update: [this does not work on Visual Studio 2017+]), or
  3. define the member functions in the template's source with the "export" keyword. Unfortunately this isn't supported by a lot of compilers. (Update: this has been removed from the standard as of C++11.)

Both 1 and 2 basically address the problem by giving the compiler access to the full code for the templated function when it is attempting to build the typed function in the program source.

Sriram Murali
  • 5,804
  • 2
  • 26
  • 32
dlanod
  • 8,664
  • 8
  • 54
  • 96
  • 4
    In (3) you have an typing error. You probably meant keyword and not keyboard. I don't see how defining the functions as 'inline' will help. You need to put them in the header or explicitly instantiate the templates using the types you need. – nimrodm Jan 19 '09 at 06:53
  • 11
    you should possibly rephrase (2). no idea what you mean by it – Johannes Schaub - litb Jan 19 '09 at 07:23
  • 1
    The "export" keyword provides the full definition as well. It may be in some slightly encoded form like a compiler parse tree but it isn't very well hidden. Of course I suppose machine code doesn't hide the source very well either. – Zan Lynx Jan 19 '09 at 23:26
  • 2
    I have the same problem, and this doesn't answer it... I don't know why this has been accepted as answer. Including the full definition of the member functions works, but, in my opinion, it represents a lack of security to our programs, and generally a bad practice that will lead to unorganized code. – Victor Mar 17 '14 at 08:30
  • I'm also confused by (2). And there seems to it since 2009 (wow, by that time I didn't know what templates are). And, putting the function into `.h` file does not help. – Tomáš Zato Jun 18 '14 at 23:53
  • 2
    @JohannesSchaub-litb if every thing needs to be in header file(defination) then what is the use of `.cpp` file? – user786 Sep 21 '16 at 10:11
  • Thank you for this simple answer, I had this same issue, but my problem was the fact that I needed to include the templated function body inside the header file, instead of a separate cpp file. – Runsva Aug 09 '22 at 18:15
23

Another option is to put the code in the cpp file and in the same cpp file add explicit instantiations of the template with the types you expect to be using. This is useful if you know you're only going to be using it for a couple of types you know in advance.

shoosh
  • 76,898
  • 55
  • 205
  • 325
  • 8
    So essentially saying *f**** ***u* to modularity, reuse, single responsibility and separation of concerns... and the whole point of generic programming which is to have generic classes which can be used with any type you want *without the template class knowing beforehand* what it is going to be used for? – jbx Oct 31 '15 at 15:51
  • 8
    @jbx I'm saying that for things like `basic_string` you're only ever going to be using it with `char` or `wchar_t` so if putting all the implementation in the header is a concern, instantiating it in the cpp is an option. The code is yours to command, not vice-versa. – shoosh Oct 31 '15 at 20:19
  • Defeats the whole point of templates in my opinion. Your example is just one exception (which should arguably have been written using overloading if its just for 2 types, but that's another argument). Template programming is supposed to be about creating something which works independently of the types it is interacting with, without knowing beforehand. Predicting what the types are going to be goes against its whole purpose. Its just a bad practice that 'solves' the pain, but just because you can doesn't mean you should. – jbx Oct 31 '15 at 20:48
  • 10
    @jbx Wrong. Template programming is about not repeating yourself. If what you write happens to be super generic and wonderful, good for you, but that is by no means necessary. If it allows me to write just one class or function instead of 2, it fulfilled its purpose. Even the standard containers are not independent of the type, they depend on things like default c'tor and move c'tor. – shoosh Nov 01 '15 at 07:46
  • You say that it is not about not repeating yourself, then in the next sentence you say that if it allows you to write just one class or function istead of 2, it fulfilled its purpose, so how is that not about not repeating yourself? How can your code follow the Open Closed Principle, if you have to modify the header file of your template each time you need to use it for another new type. Lets admit that this is a hack due to the limitation of C++, one of the annoying design flaws like many others. – jbx Nov 01 '15 at 13:43
  • @shoosh Could you give an example of such an approach? – Andrey May 24 '22 at 15:23
-1

For each file that include the .h file you should be to insert both lines:

#include "MyfileWithTemplatesDeclaration.h"
#include "MyfileWithTemplatesDefinition.cpp"

sample

#include "list.h"
    #include "list.cpp" //<---for to fix bug link err 2019



    int main(int argc, _TCHAR* argv[])
    {
        list<int> my_list;
        my_list.add_end(3);
    .
    .
    } 

also, you dont forget to place your declaration class among centinel constants

#ifndef LIST_H
#define LIST_H
#include <iostream>
.
.
template <class T>
class list
{
private:
    int m_size,
        m_count_nodes;
    T m_line;
    node<T> *m_head;
public:
    list(void);
    ~list(void);
    void add_end(T);
    void print();
};
#endif
totem_motorist
  • 161
  • 1
  • 4
  • 13
    I don't think this is a great idea. Including .cpp files sends the wrong message. If you intend the user to include both files. name them code.h and code_impl.h or similar. – Mark McKenna Mar 08 '13 at 15:21
  • 3
    I agree. There is little reason to ever have to include a .cpp file in your source, and depending on your project settings this might even give the compiler a separate headache – RectangleEquals Mar 12 '13 at 06:31