0

Possible Duplicate:
Why can templates only be implemented in the header file?

Here's my make file:


#!/usr/bin/make -f
compiler = g++
compiler_flags = -Wall -I /usr/include/c++/4.5
debug_flags = -D DEBUG -g
binary_filename = sort_testing.bin

all: clean release

release: 
    $(compiler) $(compiler_flags) main.cpp sort.o -o $(binary_filename)
debug: sort.o 
    $(compiler) $(debug_flags) $(compiler_flags) main.cpp sort.o -o $(binary_filename)
run: 
    ./$(binary_filename)
clean: 
    rm -f *.o $(binary_filename)
sort.o: 
    $(compiler) $(debug_flags) $(compiler_flags) -c sort.cpp


Here are my C++ Files:


// sort.hpp
#ifndef SORT_H
#define SORT_H

namespace sort{
    template<class T> void swap(T*,int,int);
}

#endif

// sort.cpp
#include "sort.hpp"

namespace sort{
    template<class T>
    void swap(T* items, int index_a, int index_b){
        T t = items[index_a];
        items[index_a] = items[index_b];
        items[index_b] = t;
    }
}

// main.cpp
#include <iostream>
#include <exception>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;

#include "sort.hpp"
using namespace sort;

#define NUM_INTS 5

int main(int argc, char** argv){
    try{
        cout << "\n\n\n";
        srand(time(NULL));
        int * int_coll = new int[NUM_INTS];
        for (int x = 0; x < NUM_INTS; x++)
            int_coll[x] = rand() % 100 + 1;
        cout << "Before swap" << endl;
        for (int x = 0; x < NUM_INTS; x++)
            cout << "int " << x << " == " << int_coll[x] << endl;
        cout << "\n\n\n";

        cout << "Swapping ints" << endl;
        swap<int>(int_coll, 0, 1);

        cout << "AFter swap" << endl;
        for (int x = 0; x < NUM_INTS; x++)
            cout << "int " << x << " == " << int_coll[x] << endl;
    }catch(exception& e){
        cout << "Exception:  " << e.what() << endl;
    }
    return 0;
}

And, here's my problem:

./make clean debug
rm -f *.o sort_testing.bin
g++ -D DEBUG -g -Wall -I /usr/include/c++/4.5 -c sort.cpp
g++ -D DEBUG -g -Wall -I /usr/include/c++/4.5 main.cpp sort.o -o sort_testing.bin
/tmp/ccRl2ZvH.o: In function `main':
/home/dev/c++/sorting/main.cpp:33: undefined reference to `void sort::swap<int>;(int*, int, int)'
collect2: ld returned 1 exit status
make: *** [debug] Error 1

Any idea how to resolve this issue?

Community
  • 1
  • 1
bitcycle
  • 7,632
  • 16
  • 70
  • 121

3 Answers3

1

Template definitions need to either be visible at the point of use (so that they can be implicitly instantiated) OR you need to explicitly instantiate them (in this case the linker will bring the explicit instantiation and the usage together).

In your situation I would go with option one (and implicit instantiation). This means you need to move the template definition (of the template) into the header file:

// sort.hpp
#ifndef SORT_H
#define SORT_H

namespace sort{
    template<class T>
    void swap(T*,int,int)
    {
        T t = items[index_a];
        items[index_a] = items[index_b];
        items[index_b] = t;
    }
}

#endif

Alternatively (but less useful in the general case (but has its uses)) is explicit template instantiation. Here you define in sort.cpp which variants of the template you want to have defined.

// sort.cpp
#include "sort.hpp"

namespace sort{
    template<class T>
        void swap(T* items, int index_a, int index_b){
            T t = items[index_a];
            items[index_a] = items[index_b];
            items[index_b] = t;
        }

    // Define an explicit function template instantiation.
    // Here we define that the integer version of the template must exist.
    template void swap<int>(int*,int,int);
}

This is useful when you want to limit the number of versions of a template are available.

Martin York
  • 257,169
  • 86
  • 333
  • 562
  • +1 for *explicit function template instantiation* in the source file. I didn't had this in mind. – Nawaz May 16 '11 at 07:05
0

Template definitions must be in the same file. So define the function in the header file itself.

Or include the .cpp file in the header at the bottom as:

// sort.hpp
#ifndef SORT_H
#define SORT_H

namespace sort{
    template<class T> void swap(T*,int,int);
}


#include "sort.cpp" //<--------------- this!

#endif
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • If you do this, it is often useful to rename sort.cpp so that build tools do not accidentally try and build it. – Martin York May 16 '11 at 06:26
0

You can not define templates in a .cpp file. The definition of swap should be in the sort.hpp file only. See this FAQ Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file? for more details.

Naveen
  • 74,600
  • 47
  • 176
  • 233