1

Header file for a simple template, trivial_template.hpp.

// Import packages from the C++ STL
#include <string>
#include <cstring>
#include <stdio.h>
#include <utility>
#include <limits.h>         // For std::LONG_MIN

#ifndef __TRIVIAL_TEMPLATE_H
#define __TRIVIAL_TEMPLATE_H
using namespace std;

template <typename T>
class trivial_template {
    public:
        trivial_template();
        ~trivial_template();
        static bool is_non_negative(T a_num);
        T square_given_number(T a_num);
};
#endif

Implementation file for a simple template, trivial_template.cpp.

#include "./trivial_template.hpp"

template <typename T>
trivial_template<T>::trivial_template() {
}

template <typename T>
trivial_template<T>::~trivial_template() {
}

template<typename T>
bool trivial_template<T>::is_non_negative(T a_num) {
    return (0 <= a_num);
}

template<typename T>
T trivial_template<T>::square_given_number(T a_num) {
    return (a_num*a_num);
}

The C++ main file that uses it.

#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
#include <math.h>
#include <climits>
#include <cfloat>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>

#include "../../elements/trivial_template.hpp"

using namespace std;

int main(int argc, char *argv[]) {
    cout << "   ###" << trivial_template<int>::is_non_negative(493) << "===" << endl;
    trivial_template<int> *a_ptr;
    cout << "   ###" << a_ptr->square_given_number(5) << "===" << endl;
    // 0.25^2 = 0.0625
    trivial_template<long double> *b_ptr;
    cout << "   ###" << b_ptr->square_given_number(-0.25) << "===" << endl;
    // 16.25^2 = 164.0625
    cout << "   ###" << b_ptr->square_given_number(-16.25) << "===" << endl;
    return 0;
}

My commands to compile, link, and run it are:

g++ -std=c++0x  -c  ../src/elements/trivial_template.cpp
g++ -std=c++0x  -c  ../src/test/temp/test_templates.cpp
g++ -std=c++0x  -o  ./test-boilerplate-code *.o

During linking, the following error message is produced:

Undefined symbols for architecture x86_64:
  "trivial_template<long double>::square_given_number(long double)", referenced from:
      _main in test_templates.o
  "trivial_template<int>::is_non_negative(int)", referenced from:
      _main in test_templates.o
  "trivial_template<int>::square_given_number(int)", referenced from:
      _main in test_templates.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [template] Error 1

When I tried this simple example using different paths for the location of the C++ source file, it works. Its output is:

    ###1===
    ###25===
    ###0.0625===
    ###264.062===
real         0.22
user         0.00
sys          0.00

Why is there this discrepancy? What is going on?

In addition, can you please kindly help me fix the linking error?

Thank you very much, and have a good day!

Giovanni
  • 101
  • 3
  • 13
  • Dear Mr. Günther, Can you please kindly tell me why is there a discrepancy? What did I do wrong? The question that you linked me to is helpful, but does not show a discrepancy. Thank you very much. – Giovanni Mar 30 '16 at 20:35
  • 1
    I would recommend putting your include guards above your includes. That way the includes don't get parsed twice for the same file. – Stewart Smith Mar 30 '16 at 20:50
  • 1
    http://stackoverflow.com/q/495021/179910. Some compilers can deal with templates in source files under some circumstances, but without knowing the *exact* compiler you're using, putting the entire template in the header is the safest way to make things work. – Jerry Coffin Mar 30 '16 at 20:50

1 Answers1

2

You have to put your method implementation in the header file, and include that file instead. Long story short, templates must be visible in each translation unit, just like any declarations. Also, to prevent multiple inclusion, you should use include guards in each header file.

    /*template_declarations.hpp*/
    #ifndef TEMPLATE_DECLARATIONS_HPP
    #define TEMPLATE_DECLARATIONS_HPP

    // put your declarations here

    #endif //TEMPLATE_DECLARATIONS_HPP



    /*template_implementation.hpp*/
    #ifndef TEMPLATE_IMPLEMENTATION_HPP
    #define TEMPLATE_IMPLEMENTATION_HPP

    #include "template_declarations.hpp"

    // put your implementation here

    #endif //TEMPLATE_IMPLEMENTATION_HPP

Now, you can include just the second header, or make helper header:

    /*template.hpp*/
    #ifndef TEMPLATE_HPP
    #define TEMPLATE_HPP

    #include "template_declarations.hpp"

    #endif //TEMPLATE_HPP
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
xinaiz
  • 7,744
  • 6
  • 34
  • 78
  • Dear Black Moses, Are the following an example of "include guards"? #ifndef __TRIVIAL_TEMPLATE_H #define __TRIVIAL_TEMPLATE_H ... #endif In addition, what is a "transition unit"? Thank you very much. – Giovanni Mar 30 '16 at 20:55
  • @Giovanni: Yes, those are include guards. I edited my answer so you can see the design. – xinaiz Mar 30 '16 at 20:59
  • @Giovanni It was a typo, BM meant a translation unit: a fancy way for calling the file you pass to the compiler to be compiled (as opposed to include files that are not explicitly passed to the compiler). – Kuba hasn't forgotten Monica Mar 30 '16 at 21:02
  • @KubaOber No, the translation unit is the thing you get after the preprocessor has done its work. – T.C. Mar 30 '16 at 22:25
  • @T.C. True. I'm trying to approximately simplify :) – Kuba hasn't forgotten Monica Mar 31 '16 at 12:19