Trouble with template classes (C++)

Started by
8 comments, last by ermitgilsukaru 17 years, 8 months ago
Hi. I'm new here. Hope it's not to presumptive of me to plead for help in my first post, and not in the newb-section either. I'm trying to convert my math-classes into templates and am having some troubles. I have a Matrix4x4 class with column-major data (because OpenGL wants it like that). But I prefer to view the matrix as row-major. Therefore I made an inner class, MatrixRow, to enable the C-style M[row][column] indexing. This all works fine when the code isn't templated, but I can't get it to compile when I convert it to a template. On to the code:

/// The homogenous coordinate transformation matrix. The matrix elements can be
/// accessed in C style M[row][column].
template <typename real>
class Matrix4x4 {
    public:
        // --------------- Data ------------------- //
        real m[16];
        // ---------------------------------------- //

        /// Helper-class for Matrix4x4 that makes the Matrix4x4 look like
        /// a row major array from the outside, instead of the actual column
        /// major layout that OpenGL needs.
        class MatrixRow {
            friend class Matrix4x4<real>;
            public:
                real& operator[] (int j);

            private:
                real* rowBase;
                MatrixRow() {} // Should not be created by anything besides the
                               // Matrix4x4 class.
            };


        MatrixRow operator[] (int i);
};


template <typename real>
inline real& Matrix4x4<real>::MatrixRow::operator[] (int j) {
    assert(j < 4);
    
    return *(rowBase + (j * 4));
}

template <typename real>
inline Matrix4x4<real>::MatrixRow Matrix4x4<real>::operator[] (int i) {
    assert(i < 4);

    MatrixRow row;
    row.rowBase = m + i;
    
    return row;
}
The class is heavily edited. I'm only showing the relevant code. I'd really appreciate if somebody could tell me what's wrong with this code. Also, feel free to rip on my design decisions. I'm new at this and, truth be told, I suck.
Advertisement
What error are you getting?
As was said, please post the error. One thing I notice is you don't have any const accessors shown. Also:

inline typename Matrix4x4<real>::MatrixRow Matrix4x4<real>::operator[]
I got the error error: expected initializer before 'Matrix4x4' on GCC4.0, Mac OS 10.4.7

"Matrix4x4<real>::MatrixRow" is the returntype in the declaration, so no need for typename.

I've declared a const accessor in the real class, but I didn't think it was neccessary to show it here. It's just duplicate code with a few strategally placed consts.

Anyway, thanks for at least taking the time to look at my problem.

Oh, also, how do I qoute a post on this board? The BB-tags ([QOUTE][/QOUTE]) don't seem to work.
Quote:Original post by ermitgilsukaru
"Matrix4x4<real>::MatrixRow" is the returntype in the declaration, so no need for typename.

Yes, you do need the typename keyword to disambiguate the grammer so that C++ knows to treat Matrix4x4<real>::MatrixRow as a nested type, not a member variable:
Quote:GCC 3.4.2
matrix_error.cpp:37: warning: `Matrix4x4<real>::MatrixRow' is implicitly a typename
matrix_error.cpp:37: warning: implicit typename is deprecated, please see the documentation for details
Quote:Visual C++ 8.0
matrix_error.cpp(37) : warning C4346: 'Matrix4x4<real>::MatrixRow' : dependent name is not a type
prefix with 'typename' to indicate a type

If that doesn't fix the problem (and I expect it will), can you tell us which line the error message indicates.

Σnigma
/// The homogenous coordinate transformation matrix. The matrix elements can be/// accessed in C style M[row][column].template <typename real>class Matrix4x4 {    public:        // --------------- Data ------------------- //        real m[16];        // ---------------------------------------- //        /// Helper-class for Matrix4x4 that makes the Matrix4x4 look like        /// a row major array from the outside, instead of the actual column        /// major layout that OpenGL needs.        class MatrixRow {            friend class Matrix4x4<real>;            public:                real& operator[] (int j);            private:                real* rowBase;                MatrixRow() {} // Should not be created by anything besides the                               // Matrix4x4 class.            };        MatrixRow operator[] (int i);};template <typename real>inline real& Matrix4x4<real>::MatrixRow::operator[] (int j) {//    assert(j < 4);        return *(rowBase + (j * 4));}template <typename real>inline class Matrix4x4<real>::MatrixRow Matrix4x4<real>::operator[] (int i) {//    assert(i < 4);    MatrixRow row;    row.rowBase = m + i;        return row;}


that compiles without error ...
I added class int the last function deklaration.
“Always programm as if the person who will be maintaining your program is a violent psychopath that knows where you live”
Quote:Original post by dragongame
*** Source Snippet Removed ***

that compiles without error ...
I added class int the last function deklaration.


Gcc can grok it, but it's not standard C++ and Visual C++ chokes:
Quote:Visual C++ 8.0
matrix_error.cpp(44) : fatal error C1001: An internal error has occurred in the
compiler.

The correct solution, as already posted, is to use typename.

Σnigma
Quote:Original post by ermitgilsukaru
I got the error error: expected initializer before 'Matrix4x4' on GCC4.0, Mac OS 10.4.7


Don't make us play 20 questions guessing the line this occurs on please.

Quote:"Matrix4x4<real>::MatrixRow" is the returntype in the declaration, so no need for typename.


You misunderstand when this keyword is needed. Because Matrix4x4< real > depends on the template parameter real, Matrix4x4< real >::MatrixRow becomes a dependant name. Since in this case it's a type, it becomes a dependant typename, which requires the use of this keyword. Try compiling this example in your compiler with and without the typename keyword yourself if you still don't believe me. VS2k5 will not compile it without the typename keyword.

template < typename T >class foo {public:	class bar {};		bar func();};template < typename T >typename foo< T >::bar foo< T >::func() { return bar(); }int main () {}


Quote:Oh, also, how do I qoute quote a post on this board? The BB-tags ([QOUTE][/QOUTE]) don't seem to work.


Fixed. 'nuff said.
Damn, I feel braindead. First with the spelling mistakes (quote and strategically), and second I misunderstood what Polymorphic OOP meant by the typename comment. I thought he was trying to tell me that the return type was missing.

My bad, on both counts.

I'm not at my computer right now, so I can't try the fix you all suggested.

Lastly, I wasn't being recalcitrant (imagine that, I can spell recalcitrant correctly, but not quote) with the compiler error messages; there were no line numbers in the error message.

I will post again when I'm at my computer.

It worked perfectly.

Thanks for all the help.

This topic is closed to new replies.

Advertisement