Templating classes

M

MathStuf

I am working on a class that will be a matrix based on a vector of
vectors. I am having trouble with the following code causing errors on
compilation:

template<class T> class MatrixBase
{
public:
MatrixBase()
{
width = 0;
height = 0;
matrix.clear();
}
MatrixBase(const unsigned w, const unsigned h, const T &d = T())
{
matrix.resize(w, std::vector<T>(h, d));
width = w;
height = h;
}

void AddRow(const T &d = T())
{
for (std::vector<T>::iterator i = matrix.begin(); i !=
matrix.end(); ++i)
i->push_back(d);
++height;
}
// More methods
protected:
std::vector< std::vector<T> > matrix;
unsigned height;
unsigned width;
};

In the AddRow method (and other, similar methods as well), it says
that it needs an ';' before i and that it's undeclared. It also says
that 'height' and 'width' are undeclared. Should I move the variable
definitions up to the top of the class or should the methods be
outside of it entirely?
 
V

Victor Bazarov

MathStuf said:
I am working on a class that will be a matrix based on a vector of
vectors. I am having trouble with the following code causing errors on
compilation:

template<class T> class MatrixBase
{
public:
MatrixBase()
{
width = 0;
height = 0;

Those are better initialised.
matrix.clear();

No need to clear a freshly constructed vector.
}
MatrixBase(const unsigned w, const unsigned h, const T &d = T())
{
matrix.resize(w, std::vector<T>(h, d));
width = w;
height = h;

Again, those are better initialised than assigned.
}

void AddRow(const T &d = T())
{
for (std::vector<T>::iterator i = matrix.begin(); i !=

'matrix.begin()' returns 'std::vector<std::vector<T> >::iterator.
You probably want to make this loop nested.

Also, 'std::vector<T>::iterator' is a dependent name. The compiler
doesn't know that it can be used where a type is expected. You need
to tell the compiler to trust you:

matrix.end(); ++i)
i->push_back(d);

If you don't make this loop nested (which is fine), you might want
to review what you're pushing.
++height;
}
// More methods
protected:
std::vector< std::vector<T> > matrix;
unsigned height;
unsigned width;
};

In the AddRow method (and other, similar methods as well), it says
that it needs an ';' before i and that it's undeclared.

It also says
that 'height' and 'width' are undeclared.
Where?

Should I move the variable
definitions up to the top of the class or should the methods be
outside of it entirely?

Not sure what you're asking here, sorry.

V
 
M

MathStuf

Those are better initialised.


No need to clear a freshly constructed vector.


Again, those are better initialised than assigned.

Ah, thanks.

Hmm...guess I should have looked exactly where it was getting mixed up
there. It's in the following code:


template<class T> class Matrix : public MatrixBase<T>
{
public:
Matrix()
{
width = 0;
height = 0;
matrix.clear();
}
// More methods
};

Since matrix, height, and width are protected, shouldn't they be
available to any class which inherits MatrixBase and invisible to
external interfaces? Or do I have it backwards?
Not sure what you're asking here, sorry.

I thought that the problem may have been matrix being defined after
the methods. It's a moot point now, since the typename fixed it.
 
R

red floyd

MathStuf said:
[redacted]

Hmm...guess I should have looked exactly where it was getting mixed up
there. It's in the following code:


template<class T> class Matrix : public MatrixBase<T>
{
public:
Matrix()
{
width = 0;
height = 0;
matrix.clear();
}
// More methods
};

Since matrix, height, and width are protected, shouldn't they be
available to any class which inherits MatrixBase and invisible to
external interfaces? Or do I have it backwards?

I *THINK* this is one of the rare cases where you need to qualify the
member, i.e. either MatrixBase<T>::width, or this->width.
 
R

red floyd

MathStuf wrote:
[redacted]
Hmm...guess I should have looked exactly where it was getting mixed up
there. It's in the following code:


template<class T> class Matrix : public MatrixBase<T>
{
public:
Matrix()
{
width = 0;
height = 0;
matrix.clear();
}
// More methods
};

Note that since width and height are members of MatrixBase<>, it's
probably better to let MatrixBase set them. If you need something other
than what MatrixBase has set as the "default", MatrixBase should have a
constructor with width and height parameters.
 
M

MathStuf

MathStuf wrote:

[redacted]




Hmm...guess I should have looked exactly where it was getting mixed up
there. It's in the following code:
template<class T> class Matrix : public MatrixBase<T>
{
public:
Matrix()
{
width = 0;
height = 0;
matrix.clear();
}
// More methods
};

Note that since width and height are members of MatrixBase<>, it's
probably better to let MatrixBase set them. If you need something other
than what MatrixBase has set as the "default", MatrixBase should have a
constructor with width and height parameters.

Alright, but I still have problems with their availability. I have
GetWidth() and GetHeight() methods in MatrixBase<>, but when i go to
call it, the compiler complains about it.

\Matrix.h:161: error: there are no arguments to `GetHeight' that
depend on a template parameter, so a declaration of `GetHeight' must
be available

I'm confused since MatrixBase<T> is inherited as public, and protected
members should be available (as well as public ones such as
GetHeight() and GetWidth()). I have other classes (non-template
though) where an id is inherited from the base class (public
inheritance of a protected variable) and straight calls to the id
works. Do templates mess with inheritance at all? I don't think they
would, but that's what it would seem is happening here.
 
V

Victor Bazarov

MathStuf said:
MathStuf wrote:

[redacted]




Hmm...guess I should have looked exactly where it was getting mixed
up there. It's in the following code:
template<class T> class Matrix : public MatrixBase<T>
{
public:
Matrix()
{
width = 0;
height = 0;
matrix.clear();
}
// More methods
};

Note that since width and height are members of MatrixBase<>, it's
probably better to let MatrixBase set them. If you need something
other than what MatrixBase has set as the "default", MatrixBase
should have a constructor with width and height parameters.

Alright, but I still have problems with their availability. I have
GetWidth() and GetHeight() methods in MatrixBase<>, but when i go to
call it, the compiler complains about it.

\Matrix.h:161: error: there are no arguments to `GetHeight' that
depend on a template parameter, so a declaration of `GetHeight' must
be available

That's just not true. 'GetHeight' is non-static, so it *does* have
one argument that depends on the template argument - the instance of
the class (the object). But it doesn't really matter. The full name
I'm confused since MatrixBase<T> is inherited as public, and protected
members should be available (as well as public ones such as
GetHeight() and GetWidth()). I have other classes (non-template
though)

That's *the* difference.
where an id is inherited from the base class (public
inheritance of a protected variable) and straight calls to the id
works. Do templates mess with inheritance at all?

No, but they do have slightly different rules for name lookup.
I don't think they
would, but that's what it would seem is happening here.

No, you just need to learn name lookup rules.

V
 
M

MathStuf

MathStuf said:
MathStuf wrote:
[redacted]
Hmm...guess I should have looked exactly where it was getting mixed
up there. It's in the following code:
template<class T> class Matrix : public MatrixBase<T>
{
public:
Matrix()
{
width = 0;
height = 0;
matrix.clear();
}
// More methods
};
Note that since width and height are members of MatrixBase<>, it's
probably better to let MatrixBase set them. If you need something
other than what MatrixBase has set as the "default", MatrixBase
should have a constructor with width and height parameters.
Alright, but I still have problems with their availability. I have
GetWidth() and GetHeight() methods in MatrixBase<>, but when i go to
call it, the compiler complains about it.
\Matrix.h:161: error: there are no arguments to `GetHeight' that
depend on a template parameter, so a declaration of `GetHeight' must
be available

That's just not true. 'GetHeight' is non-static, so it *does* have
one argument that depends on the template argument - the instance of
the class (the object). But it doesn't really matter. The full name
of 'GetHeight' is 'MatrixBase<T>::GetHeight', which means it *does*
depend on 'T' (simply because it is a member of the template).

Okay...I put MatrixBase<T>:: scoping on all references to height,
width, and matrix, and it seems to work fine now. Thanks for all the
help.

--MathStuf
 
D

David C.

Also, 'std::vector<T>::iterator' is a dependent name. The compiler
doesn't know that it can be used where a type is expected. You need
to tell the compiler to trust you:

for (typename std::vector<T>::iterator ...
^^^^^^^^

This is one of the reasons I like to use typedefs. It makes the code
easier to read and removes ambiguities. For example

template<class T> class MatrixBase
{
protected:
typedef std::vector<T> matrixrow_t;
typedef std::vector<matrixrow_t> matrix_t;

matrix_t matrix;
...

public:
void AddRow(const T &d = T())
{
for(matrix_t::iterator i = matrix.begin();
i != matrix.end(); ++i)
{
i->push_back(d);
}
++height;
}
...
};

Doing this would also make another error in the OP's code more obvious:

matrix.begin() returns an iterator to a std::vector< std::vector<T> >,
not an iterator to a std::vector<T>.

Using typedefs, you'd probably notice that bug without ever even running
it through the compiler.

-- David
 
V

Victor Bazarov

David said:
This is one of the reasons I like to use typedefs. It makes the code
easier to read and removes ambiguities. For example

template<class T> class MatrixBase
{
protected:
typedef std::vector<T> matrixrow_t;
typedef std::vector<matrixrow_t> matrix_t;

matrix_t matrix;
...

public:
void AddRow(const T &d = T())
{
for(matrix_t::iterator i = matrix.begin();

I believe you still have to use 'typename':

for (typename matrix_t::iterator i = matrix.begin();
i != matrix.end(); ++i)
{
i->push_back(d);
}
++height;
}
...
};

[..]

-- David

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,163
Latest member
Sasha15427
Top