Implement operator= overloading outside class

Hi all, I'm having a hard time trying to code c++ into split files. Following is my header file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template <class T> 
class Matrix {
   	
	int w, h;
	T* m;

  public:

	  Matrix (int _w=0, int _h=0, int v=0);

	  Matrix<T>& operator= (Matrix &M){
	    w = M.w;
	    h = M.h;
	    m = (T*) malloc(sizeof(T)*w*h);
	    for (int i=0; i<h; i++)
	      for (int j=0; j<w; j++)
		m[i*w + j] = M.m[i*w + j];
	    return *this;
	  }
};


Whenever I try to implement the operator= code outside the class, in a .cpp file like that:

1
2
3
4
5
6
7
8
9
10
template <class T>
Matrix<T>& Matrix<T>::operator= (Matrix &M){
    w = M.w;
    h = M.h;
    m = (T*) malloc(sizeof(T)*w*h);
    for (int i=0; i<h; i++)
        for (int j=0; j<w; j++)
            m[i*w + j] = M.m[i*w + j];
    return *this;
}


I get this error:
undefined reference to `Matrix<int>::operator=(Matrix<int>&)'

Can anyone tell me how to do that?
Thanks!
A couple of points.

1. Your operator= should take a const reference, as the compiler will attempt to generate one for you.

2. Your template definition will need to be available to all compiled units. The easiest way to do this is to make it inline and move it to a header file. Another way to do it is force your library (or program) to include a pre-instantiated copy. This is how your standard C++ library makes std::string and std::wstring available.
Thanks for reply. Could you tell me more about this pre-instantiated copy? Or point me out some reference where can I understand all these stuff?
I couldn't find any links on this, I find that amazing!

Anyway, here's an example I knocked up. Number is a simple template class with a couple of methods, and we declare a couple of instances of this class. The impementation is in a seperate compiled unit, where the template implementation resides and a couple of instances are created (for int and double).

main() comes along and uses the code, seeing only the header and hopes the linker can sort it all out. The linker uses the instantiated int version, but can't find a long instantiation and generates an error.

The catch is that you can use this in libraries. That is how sting and wstring are instances of basic_string but still manage to be exported as code.

x.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <class T>
class Number
{
public:
	Number(const T& n);
	T	get_value() const;

private:
	T	value;
};

#ifndef CREATE_INSTANCE
extern template class Number<int>;
extern template class Number<double>;
#endif 


x.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#define CREATE_INSTANCE
#include "x.hpp"

template <class T>
Number<T>::Number(const T &n)
	:	value(n)
{
}

template <class T>
T Number<T>::get_value() const
{
	return value;
}

template class Number<int>;
template class Number<double>;


xmain.cpp
1
2
3
4
5
6
7
8
9
#include "x.hpp"

int main()
{
	Number<int> ni(1); // used pre-instantiated code
	Number<long> nl(1); // generates link-time error

	return 0;
}

Last edited on
@KBW - Are you sure?? I don't think your code above does anything in particular.


(ps string and wstring are typedefs - certainly in MSVC)
Sure - they are typedefs for a basic_string instantiated on a char.
But somewhere there has to be a compiled version of the non-inlined methods on basic_string -- and that is in the c++ runtime library.
Yes, I am sure.

In main(), variable ni links to the preinstantiated Number<int>, whereas nl generates a link error because there is no instance of Number<long>.

Have you tried my example, or have you just browsed the code?
I tried it (MSVC).
Ok, I've edited the x.hpp and x.cpp by adding CREATE_INSTANCE for MSVC support.

Under MSVC:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
C:\cygwin\tmp>cl xmain.cpp x.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

xmain.cpp
x.cpp
Generating Code...
Microsoft (R) Incremental Linker Version 8.00.50727.762
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:xmain.exe
xmain.obj
x.obj
xmain.obj : error LNK2019: unresolved external symbol "public: __thiscall Number<long>::Number<long>(long const &
QAE@ABJ@Z) referenced in function _main
xmain.exe : fatal error LNK1120: 1 unresolved externals 


Under g++
1
2
3
4
$ g++ xmain.cpp x.cpp -o x
/cygdrive/c/DOCUME~1/TEMP/LOCALS~1/Temp/ccmDRJdM.o:xmain.cpp:(.text+0x58): undefined reference to `Number<long>::
Number(long const&)'
collect2: ld returned 1 exit status 
Topic archived. No new replies allowed.