0

I am fairly new to C++. I tried to create a library with a few functions and classes.

In the visual studio solution, I created another console project, included the library, it worked for the first few times, but as I created more source files, the linker gives me LNK 2019 errors of unresolved external symbols.

I have implemented all the functions in my header files and classes, what possibly could go wrong? Here is my includes

TS.h

/* I include "TS.h" in the console project */
#pragma once
#include "TMiscFunc.h"
#include "TFraction.h"

TFraction.h

 #pragma once
    #include <iostream>
    #include "TMiscFunc.h"
    namespace TS {
    //The class which simulates a fraction
    }

TFraction.cpp

#include "TFraction.h"

    //Implementation of the functions of TFraction.h

TMiscFunc.h

namespace TS {


template <typename T0> T0 TAbsolute(T0 value);
template <typename T0> T0 TCeiling(T0 value);
template <typename T0> T0 TFloor(T0 value);
template <typename T0> T0 TPower(T0 value, int power);

TMiscFunc.cpp

#include "TMiscFunc.h"

 template <typename T0> T0 TAbsolute(T0 value) {
    //operations...
}
template <typename T0> T0 TCeiling(T0 value) {
    //operations...
}

template <typename T0> T0 TFloor(T0 value) {
    //operations...
}

template <typename T0> T0 TPower(T0 value, int power) {
    //operations...
}

The error messages:

Error   LNK2019 unresolved external symbol "int __cdecl 
TS::TAbsolute<int>(int)" (??$TAbsolute@H@TS@@YAHH@Z) 
referenced in function "public: void __thiscall 
TS::TFraction::Simplify(void)" (? 
Simplify@TFraction@TS@@QAEXXZ)

All the errors are the same except the function names are changed

Thank you all for reading.

//It is solved

  • 1
    Show all the code (see [mcve]). – TypeIA Jul 27 '18 at 03:31
  • 1
    Essentially, for templates, the compiler generate the code when it is used provide that the definition is visible. If not, you have to explicitly instantiate the template. Usually, templates are defined in header files to avoid that problem. – Phil1970 Jul 27 '18 at 03:32
  • I have updated the header file here, is that my declarations are not valid in the header file? –  Jul 27 '18 at 03:38
  • Templates have to be fully defined in the header. You need the implementation (the thing you'd normally put in a cpp file for non-templated stuff) to be in the header. – Silvio Mayolo Jul 27 '18 at 03:39
  • I put the template functions implementations into the header files, it worked perfectly, thank you everyone here! –  Jul 27 '18 at 03:44

1 Answers1

0

Here is a minimal, complete and verifiable example to demonstrate the above situation. It's Linux + gcc based so the text in the link errors is a bit different, but other than that it's just the same. Here are the files:

$ ls
Fraction.cpp  Fraction.h  Fraction_Int.h  main.cpp

and their contents:

$ cat Fraction.cpp
template<typename T0> T0 Floor(T0 value){ return value; }

$ cat Fraction.h
#ifndef __FRACTION_H__
#define __FRACTION_H__    
template<typename T0> T0 Floor(T0 value);    
#endif

$ cat Fraction_Int.h
#ifndef __FRACTION_INT_H__
#define __FRACTION_INT_H__    
class Fraction_Int {
public:
    int nom;
    int denom;
};    
#endif

$ cat main.cpp
#include "Fraction.h"
#include "Fraction_Int.h"
int main(int argc, char **argv)
{
    Fraction_Int fi;
    Floor<Fraction_Int>(fi);
    return 0;
}

When I compile it like that I get:

$ g++ -o main main.cpp Fraction.cpp
/tmp/cc4fLBk5.o: In function `main':
main.cpp:(.text+0x26): undefined reference to `Fraction_Int Floor<Fraction_Int>(Fraction_Int)'
collect2: error: ld returned 1 exit status

Then I put the implementation inside the h file:

$ cat Fraction.h
#ifndef __FRACTION_H__
#define __FRACTION_H__
template<typename T0> T0 Floor(T0 value){ return value; }
#endif

$ cat Fraction.cpp
//template<typename T0> T0 Floor(T0 value){ return value; }

And when I compile everything is OK ...

OrenIshShalom
  • 5,974
  • 9
  • 37
  • 87