0

When trying to compile the code below, I get the following error:

$ g++ -std=c++11 main.cpp src/matrix.cpp
/tmp/ccsVOKfQ.o: In function `main':
main.cpp:(.text+0x1b): undefined reference to `matrix<int>::matrix(unsigned int, int)'
main.cpp:(.text+0x2c): undefined reference to `matrix<int>::operator[](int)'
collect2: error: ld returned 1 exit status

As far as I know all the code is included correctly, it even worked fine in Visual Studio, but for some reason refuses to compile in GCC on Linux, giving the above error.

My Code:

src/matrix.hpp:

#ifndef __matrix_hpp
#define __matrix_hpp
#include <vector>
#include "../lib/typedefs.hpp"

// abstraction layer on top of 2D vector
template <typename t>
class matrix {
private:
  std::vector<std::vector<t>> _mat;
  uint _size;
public:
  matrix(uint, t);
  std::vector<t> get_row(int);
  std::vector<t> get_column(int);
  std::vector<t>& operator[](int);
  matrix transpose();
};

#endif

src/matrix.cpp:

#include "matrix.hpp"

template <typename t>
matrix<t>::matrix(uint size, t default_val) {
  _size = size;
  _mat = std::vector<std::vector<t>>(_size, std::vector<t>(_size, default_val));
}

template <typename t>
std::vector<t> matrix<t>::get_row(int row_number) {
  return _mat[row_number];
}

template <typename t>
std::vector<t> matrix<t>::get_column(int col_number) {
  std::vector<t> column;

  for (int r = 0; r < _size; r++)
    column.push_back(_mat[r][col_number]);

  return column;
}

// provided as alternative notation to get_row
template <typename t>
std::vector<t>& matrix<t>::operator[](int i) {
  return get_row(i);
}

main.cpp:

#include <iostream>
#include <cstdio>
#include "src/matrix.hpp"

int main() {
  matrix<int> m(9, 0); // test constructor
  m[1][2] = 100; // test operator overload
  return 0;
}

How can I resolve this issue and make the code compile?

Electric Coffee
  • 11,733
  • 9
  • 70
  • 131
  • You need to instantiate the template. Try putting `template class matrix;` in the matrix.cpp. – bialpio Nov 15 '14 at 01:02
  • @bialpio but `int` is not the type I'm gonna use every time, what good is it in the matrix.cpp file? – Electric Coffee Nov 15 '14 at 01:05
  • 1
    @ElectricCoffee No good. Just put the definitions in the header file. – David G Nov 15 '14 at 01:08
  • 2
    When you explicitly instantiate a class template, as @bialpio suggests, the linker will be able to find the definition. Obviously, that means your class template can only be instantiated with a predetermined set of types. If you don't want that restriction, move the implementation of the member functions to the header. You should also read [this](https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier) (`__matrix_hpp` violates the rules mentioned in there). – Praetorian Nov 15 '14 at 01:09
  • And I don't believe that the code used to compile in its current form on MSVC. Maybe you were #including `src/matrix.cpp` instead of `src/matrix.hpp`? – Praetorian Nov 15 '14 at 01:10
  • As an addition to all the other comments you may wish to read the answers to this [Stackoverflow question](http://stackoverflow.com/questions/115703/storing-c-template-function-definitions-in-a-cpp-file) . – Michael Petch Nov 15 '14 at 01:15
  • @Praetorian no, it definitely included the header file, the code was unchanged, so what it says in the header is what it said back on windows too – Electric Coffee Nov 15 '14 at 01:16
  • @ElectricCoffee then you need to either explicitly instantiate the template with all the types you want to use it with (should be viable if you want to use the matrix class for math calculations), or move the implementation to the header. – bialpio Nov 15 '14 at 01:22
  • I'd be surprised if it worked on even MSVC. There is one thing I do note is absent and I'm curious what you have in it. You reference typedefs.hpp in an include but the code isn't present. Almost wonder if something in that header makes it work. – Michael Petch Nov 15 '14 at 01:35

0 Answers0