Asked  7 Months ago    Answers:  5   Viewed   26 times

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?

 Answers

94

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.

Tuesday, June 1, 2021
 
Corsair
answered 7 Months ago
23

I found another forum post, where somebody seems to have reported the same exact problem that you are having. Please check to see if you have

_DEBUG

defined either in your project settings (under C/C++ -- Preprocessor) or somewhere in your code (or include files).

It looks as if std::vector thinks you are building a debug build, when you are in fact creating a release build.

I hope this helps.

Monday, June 14, 2021
 
tpow
answered 6 Months ago
23

Due to a weirdness in C++'s compilation model, you cannot separate out .h and .cpp files very cleanly for template classes. Specifically, any translation unit (C++ source file) that wants to use a template class has to have access to the entire template definition. This is a strange quirk of the language, but unfortunately it's here to stay.

One option is to put the implementation up in the header file rather than in the source, then to not have a .cpp file at all. For example, you might have this header:

#pragma once
#ifndef hijo_h
#define hijo_h

template <class A>
class hijo
{
public:
    hijo(void);
    ~hijo(void);
};

/* * * * Implementation Below This Point * * * */

template <class A>
hijo<A>::hijo(void)
{
}
template <class A>
hijo<A>::~hijo(void)
{
}

#endif

Hope this helps!

Monday, August 23, 2021
 
Peter Lawrey
answered 4 Months ago
15

I encountered the same error using Python 3.6 with 3.0.0 Matplotlib and PyCharm 2018.2.4. The error is evidently on the Pycharm side, as indicated by the traceback and by the fact that importing matplotlib via the anaconda prompt or spyder IDE does not produce this error.

The 'switch backend' utility seems to be a new feature according to the release notes of matplotlib https://github.com/matplotlib/matplotlib/releases. As pointed out in @Psychotechnopath's answer, it might be some issue with the path, so that Pycharm can't find the switch backend module when it is called by the Pycharm scripts in your Traceback.

However I don't think manually adding anything to the path is a desirable and robust solution. Instead, I downgraded matplotlib to version 2.2.3 using the conda installer in the Anaconda Prompt:

conda install matplotlib=2.2.3

After this downgrade I was able to import matplotlib in Pycharm again without any issues.

Monday, October 11, 2021
 
phuongzzz
answered 2 Months ago
79

This is normal and expected.

14 Templates
6 A function template, member function of a class template, variable template, or static data member of a class template shall be defined in every translation unit in which it is implicitly instantiated (14.7.1) unless the corresponding specialization is explicitly instantiated (14.7.2) in some translation unit; no diagnostic is required.

As applied to your case, this means that when the explicit instantiation of templ is removed, the compiler can either

  1. generate an instantiation normally because of the implicit instantiation in the same TU; or
  2. inline the call to templ and not generate any externally usable entity.

Either behaviour is permitted for a conforming implementation. If you make sure there's an explicit instantiation somewhere, either will produce valid object code. If you don't, you may or may not get an error and it's your own fault.

Monday, November 15, 2021
 
Shafeeq Mohammed
answered 2 Weeks ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share