Thread: trouble with matrix template class

  1. #1
    Registered User
    Join Date
    May 2009
    Posts
    242

    trouble with matrix template class

    I started off trying to do this for rectangular matrices but ran into too many problems, so I backed up to square matrices and moved the dimension into the template specification. But I still can't get the main constructor to work.

    First, here's my incipient header file:
    Code:
    #ifndef MATRIX_H
    #define MATRIX_H
    
    template<typename T, int n> // is the Matrix height/width
    class Matrix
    {
    private:
    	T** content;	// 2-dimensional array of T objects
    public:
    	// no default constructor because we don't know what T is
    	// construct a Matrix from an array
    	Matrix(const T arr[][n]);
    	// copy constructor
    	Matrix(const Matrix& m);
    	// destructor
    	~Matrix();
    
    	// basic matrix operations
    	// addition
    	Matrix<T, n> operator+(const Matrix<T, n>& m) const;
    
    	// other methods
    	void show();
    };
    #endif
    Now here's the relevant constructor definition:
    Code:
    template<typename T, int n>
    Matrix<T, n>::Matrix(const T arr[][n])
    {	
    	if (n > 0)	// validate input at least a little
    	{
    		// copy contents (!)
    		// allocate memory
    		T** cont_arr = new T*[n];
    		for (int i = 0; i < n; ++i)
    		{
    			cont_arr[i] = new T[n];
    		}
    		// set values
    		for (int i = 0; i < n; ++i) // rows
    		{
    			for (int j = 0; j < n; ++j) // columns
    			{
    				cont_arr[i][j] = arr[i][j];
    			}
    		}
    		content = cont_arr;
    	}
    	else	// bad value for n
    	{
    		std::cout << "Error! Matrix dimension must be > 0.\n";
    		content = 0;
    	}
    }
    Now here's main with the problematic part commented out:
    Code:
    #include <iostream>
    #include "matrix.h"
    
    int main()
    {
    	int arr1[3][3] = {{1,2,3}, {4,5,6}, {7,8,9}};
    	int arr2[3][3] = {{10,9,8},{20,19,18}, {30,29,28}};
    /*
    	Matrix<int, 3> matrix1(arr1);
    	Matrix<int, 3> matrix2(arr2);
    // */
    It compiles in this form, but as soon as I uncomment the creation of the actual Matrix objects, I get a long drawn-out error message:

    error LNK2001: unresolved external symbol "public: __thiscall Matrix<int,3>::~Matrix<int,3>(void)" (??1?$Matrix@H$02@@QAE@XZ)

    I'm not understanding the problem here... probably something really stupid

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > Now here's the relevant constructor definition:
    And where is the relevant destructor?

    The error message is looking for the dtor
    public: __thiscall Matrix<int,3>::~Matrix<int,3>(void)" (??1?$Matrix@H$02@@QAE@XZ)
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    May 2009
    Posts
    242
    Code:
    // destructor
    template<typename T, int n>
    Matrix<T, n>::~Matrix()
    {
    	// free memory on each row
    	for (int i = 0; i < n; ++i)
    	{
    		delete [] content[i];
    		content[i] = 0;
    	}
    	// delete content entirely
    	delete [] content;
    	content = 0;
    }
    i had it in there, just didn't post because i didn't see how it could be the problem.

  4. #4
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Practically, with most compilers, code that uses a class template needs to have visibility of the definitions of that class' member functions at compile time.

    In other words, the implementation of your classes constructors and destructors needs to be within the header file. Although you haven't said it explicitly, you are placing the implementation into another file, so they are not visible when compiling the main() function. A shortcut to doing that is #include "matrix.cc" (if that is the name of the function that implements your member functions) within "matrix.h".
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Also, just as a hint, it would be better to use std::<vector< std::vector<T> > instead of T**.

    grumpy, I'm curious. Whyever did you assume that the file would have a .cc ending? I never see it anywhere.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Elysia
    Whyever did you assume that the file would have a .cc ending? I never see it anywhere.
    It is another somewhat commonly used file extension for C++ source files, along with .cpp and .cxx. (I doubt if .C has much popularity at all.)
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    So I am told, but I have never seen it. I always think of ".cpp" as the obvious extension.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    Better to change the extention to something other than cc or cpp. You don't want your idea to try to build your template implementation as a separate file. True, it's harmless to do so, as the resultant compilation unit will be empty, but what for?

    I personally use .hpp for template definition files. (and .h for normal header files).
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  9. #9
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by Elysia View Post
    grumpy, I'm curious. Whyever did you assume that the file would have a .cc ending? I never see it anywhere.
    I just picked, at random, one of the common extensions used for C++ files. Another day, I might pick another extension at random.

    .cc is a fairly commonly used extension for C++ source files in the unix world, just as .cpp is fairly common in the windows world.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  10. #10
    Registered User
    Join Date
    May 2009
    Posts
    242
    ok, i guess first: i would've preferred using vectors, too, but this was a challenge to see how to build a matrix class from arrays. I actually don't even think the challenge was to do it as template (which i wrongly didn't think would be so hard), so i'm first backing up and doing it in the more specific case of doubles.

    I've finally gotten it to work in that case, and one thing i've noticed is that if i make my "array" constructor MatrixDbl1(double** d, int n); the compiler won't accept an an array of doubles just declared in main with the easy
    Code:
    double arr1[3][3] = {{1.0, 2.0, 3.0}, ... };
    It works, though, if in main() I declare double** arr1 = new double*[3];
    and then go through and dynamically assign appropriate memory to the pointers as i did in the constructor.
    Seems weird to me that it doesn't like the array version, but I couldn't get it to work that way.
    I'll see if grumpy's suggestion of adding #include "matrix.cpp" (with my typical windows extension) works for the template, which is really more fun than making it just doubles.

  11. #11
    Registered User
    Join Date
    May 2009
    Posts
    242
    yep, grumpy's suggestion worked immediately. tx!

    better just to stick the function definitions in the .h file from the beginning here?

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by Aisthesis View Post
    ...I've finally gotten it to work in that case, and one thing i've noticed is that if i make my "array" constructor MatrixDbl1(double** d, int n); the compiler won't accept an an array of doubles just declared in main with the easy
    Code:
    double arr1[3][3] = {{1.0, 2.0, 3.0}, ... };
    It works, though, if in main() I declare double** arr1 = new double*[3];
    and then go through and dynamically assign appropriate memory to the pointers as i did in the constructor.
    Seems weird to me that it doesn't like the array version, but I couldn't get it to work that way.
    I'll see if grumpy's suggestion of adding #include "matrix.cpp" (with my typical windows extension) works for the template, which is really more fun than making it just doubles.
    Because a 2D array isn't a pointer to pointer:
    http://cboard.cprogramming.com/c-pro...tml#post925712

    Quote Originally Posted by Aisthesis View Post
    yep, grumpy's suggestion worked immediately. tx!

    better just to stick the function definitions in the .h file from the beginning here?
    For templates, probably.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Assignment issues
    By Elysia in forum C++ Programming
    Replies: 6
    Last Post: 01-13-2010, 12:55 PM
  2. Function template has already been defined
    By Elysia in forum C++ Programming
    Replies: 19
    Last Post: 04-14-2009, 10:17 AM
  3. Default class template problem
    By Elysia in forum C++ Programming
    Replies: 5
    Last Post: 07-11-2008, 08:44 AM
  4. Class Template Trouble
    By pliang in forum C++ Programming
    Replies: 4
    Last Post: 04-21-2005, 04:15 AM
  5. Operator overloading in template classes
    By moejams in forum C++ Programming
    Replies: 5
    Last Post: 07-21-2003, 05:16 PM