Returning a template depending on arguments

D

daniele lugli

Dear all,
this class:

template<int m, int n>
class SmallMatrix
{
typedef double myData [m] [n];
myData M;

public:
SmallMatrix () {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
M[j] = 0.;
}
}
}
virtual ~SmallMatrix () {}
operator myData & () {
return M;
}
operator const myData & () const {
return M;
}
};

compiles fine with g++-4.4.3 and does what I expect it to do, eg I can
declare a SmallMatrix<3,4> m; and then access its elements as m[j].

Then I tried to add an operator* like this:

SmallMatrix<m, n1> operator* (const SmallMatrix<n, n1> & f) const {
SmallMatrix<m, n1> result;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n1; j++) {
result[j] = 0.;
for (int k = 0; k < n; k++) {
result[j] += M[k] * f[k][j];
}
}
}
return result;
}

what I would like to do is:

SmallMatrix<2, 3> m23;
SmallMatrix<3, 4> m34;
SmallMatrix<2, 4> m24;
....
m24 = m23 * m34;

but the class SmallMatrix with the operator* method in it does not
compile; I get:
'n1' was not declared in this scope
template argument 2 is invalid

clearly because n1 is not known before it appears in the return type
declaration; it becomes known only after the argument of operator* is
parsed.

I cannot see any way of getting what I would like to have. Is it
possible or it is one of the things one cannot do with c++?

TYIA
 
A

Alain Ketterlin

daniele lugli said:
template<int m, int n>
class SmallMatrix
{
[...]
};
SmallMatrix<m, n1> operator* (const SmallMatrix<n, n1> & f) const {
[...]
}

This can't work because, for a given (n,m), there must be one
instanciation of op* for each value of n1. You have to make it a
template member, i.e.,

template <int n1> SmallMatrix<m, n1> operator* ...

-- Alain.
 
D

daniele lugli

daniele lugli said:
template<int m, int n>
class SmallMatrix
{
    [...]
};
   SmallMatrix<m, n1> operator* (const SmallMatrix<n, n1> & f) const {
          [...]
   }

This can't work because, for a given (n,m), there must be one
instanciation of op* for each value of n1. You have to make it a
template member, i.e.,

template <int n1> SmallMatrix<m, n1> operator* ...

-- Alain.

Your suggestion works pretty fine:

template<int m, int n>
class SmallMatrix
{
typedef double myData [m] [n];
myData M;

public:
SmallMatrix () {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
M[j] = 0.;
}
}
}
virtual ~SmallMatrix () {}
operator myData & () {
return M;
}
operator const myData & () const {
return M;
}
SmallMatrix & operator= (const SmallMatrix & rhs) {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
M[j] = rhs[j];
}
}
return *this;
}
template<int n1>
SmallMatrix<m, n1> operator* (const SmallMatrix<n, n1> & f) const {
SmallMatrix<m, n1> result;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n1; j++) {
result[j] = 0.;
for (int k = 0; k < n; k++) {
result[j] += M[k] * f[k][j];
}
}
}
return result;
}
};

Merci beaucoup!
 
N

Noah Roberts

Dear all,
this class:

template<int m, int n>
class SmallMatrix
{
        typedef double myData [m] [n];
        myData M;

public:
        SmallMatrix () {
                for (int i = 0; i < m; i++) {
                        for (int j = 0; j < n; j++) {
                                M[j] = 0.;
                        }
                }
        }
        virtual ~SmallMatrix () {}
        operator myData & () {
                return M;
        }
        operator const myData & () const {
                return M;
        }

};


This entire class of yours can be replaced by this single line of
code:
;

That's right, a noop.

Now I'll use it:

double matrix0[10][5] = {};

Your class offers nothing over this implementation. The encapsulation
benefit you'd normally get from implementing a matrix class is
entirely destroyed by your conversion operator, an obviously misjudged
attempt to force [][] syntax into the equation. Quite the contrary in
fact, your class provides for some interesting avenues for unexpected
behavior.

Reconsider your conversion operator and attempt to gain [][] syntax.
 
D

daniele lugli

Dear all,
this class:
template<int m, int n>
class SmallMatrix
{
        typedef double myData [m] [n];
        myData M;
public:
        SmallMatrix () {
                for (int i = 0; i < m; i++) {
                        for (int j = 0; j < n; j++) {
                                M[j]= 0.;
                        }
                }
        }
        virtual ~SmallMatrix () {}
        operator myData & () {
                return M;
        }
        operator const myData & () const {
                return M;
        }


This entire class of yours can be replaced by this single line of
code:
;

That's right, a noop.

Now I'll use it:

double matrix0[10][5] = {};

Your class offers nothing over this implementation.


Not true.
My minimal example offers matrix multiplication; matrix-vector
multiplication (over a similar SmallVector template class) and other
similar operations can be added.
The compiler checks that such operations are made with the correctly
sized types.
 The encapsulation
benefit you'd normally get from implementing a matrix class is
entirely destroyed by your conversion operator,

I have no reason to completely hide the data: accessing directly via []
[] is a simple and overhead-free way to fill or read the entries.
an obviously misjudged
attempt to force [][] syntax into the equation.

Why 'attempt'? It works.
 Quite the contrary in
fact, your class provides for some interesting avenues for unexpected
behavior.

Examples please.
Reconsider your conversion operator and attempt to gain [][] syntax.

Maybe through an operator[] returning a row selector object, having in
turn an operator[] ?
This could leave place to add some bound-checking code.
But I don't need bound-checking here and I don't want the overhead of
this mechanism.
What I want is just to avoid rewriting the loops for matrix
operations.
 
R

Richard Damon

Dear all,
this class:

template<int m, int n>
class SmallMatrix
{
typedef double myData [m] [n];
myData M;

public:
SmallMatrix () {
for (int i = 0; i< m; i++) {
for (int j = 0; j< n; j++) {
M[j] = 0.;
}
}
}
virtual ~SmallMatrix () {}
operator myData& () {
return M;
}
operator const myData& () const {
return M;
}
};

compiles fine with g++-4.4.3 and does what I expect it to do, eg I can
declare a SmallMatrix<3,4> m; and then access its elements as m[j].

Then I tried to add an operator* like this:

SmallMatrix<m, n1> operator* (const SmallMatrix<n, n1> & f) const {
SmallMatrix<m, n1> result;
for (int i = 0; i< m; i++) {
for (int j = 0; j< n1; j++) {
result[j] = 0.;
for (int k = 0; k< n; k++) {
result[j] += M[k] * f[k][j];
}
}
}
return result;
}

what I would like to do is:

SmallMatrix<2, 3> m23;
SmallMatrix<3, 4> m34;
SmallMatrix<2, 4> m24;
...
m24 = m23 * m34;

but the class SmallMatrix with the operator* method in it does not
compile; I get:
'n1' was not declared in this scope
template argument 2 is invalid

clearly because n1 is not known before it appears in the return type
declaration; it becomes known only after the argument of operator* is
parsed.

I cannot see any way of getting what I would like to have. Is it
possible or it is one of the things one cannot do with c++?

TYIA



I think you want operator* to be declared as

template<int n1> SmallMatrix<m, n1> operator*(const SmallMatrix<n,n1>&
f) const {
....

as you are introducing another template parameter into the code, so need
to have nested templates.

The more canonical method would be to make operator * a free function
(maybe a friend) declared outside the class as:

template<int m, int n, int n1> SmallMatrix<m, n1> operator*(const
SmallMatrix<m,n>& f, const SmallMatrix<n,n1>& g){
....

so that if there is a class convertible to SmallMatrix it can use the
operator*
 
N

Noah Roberts

Dear all,
this class:
template<int m, int n>
class SmallMatrix
{
        typedef double myData [m] [n];
        myData M;
public:
        SmallMatrix () {
                for (int i = 0; i < m; i++) {
                        for (int j = 0; j <n; j++) {
                                M[j] = 0.;
                        }
                }
        }
        virtual ~SmallMatrix () {}
        operator myData & () {
                return M;
        }
        operator const myData & () const {
                return M;
        }
};

This entire class of yours can be replaced by this single line of
code:
;
That's right, a noop.
Now I'll use it:
double matrix0[10][5] = {};
Your class offers nothing over this implementation.

Not true.
My minimal example offers matrix multiplication; matrix-vector
multiplication (over a similar SmallVector template class) and other
similar operations can be added.
The compiler checks that such operations are made with the correctly
sized types.


And none of that adds anything. I can do all that with the array. In
fact, I'd be better off doing so since I'm not relying on silent
conversion operators to break encapsulation.
 The encapsulation
benefit you'd normally get from implementing a matrix class is
entirely destroyed by your conversion operator,

I have no reason to completely hide the data: accessing directly via []
[] is a simple and overhead-free way to fill or read the entries.
Then why not just leave the variable public?
an obviously misjudged
attempt to force [][] syntax into the equation.

Why 'attempt'? It works.

Does it?
Examples please.

As with all classes that offer implicit conversion operators, your
conversion sequence will be used silently when perhaps it should not.
Reconsider your conversion operator and attempt to gain [][] syntax.

Maybe through an operator[] returning a row selector object, having in
turn an operator[] ?

Or, I don't know, a function?
This could leave place to add some bound-checking code.
But I don't need bound-checking here and I don't want the overhead of
this mechanism.

Because you've measured it and know that it's a problem, right?
What I want is just to avoid rewriting the loops for matrix
operations.

And...?
 
D

daniele lugli

I think you want operator* to be declared as

template<int n1> SmallMatrix<m, n1> operator*(const SmallMatrix<n,n1>&
f) const {
...

as you are introducing another template parameter into the code, so need
to have nested templates.

The more canonical method would be to make operator * a free function
(maybe a friend) declared outside the class as:

template<int m, int n, int n1> SmallMatrix<m, n1> operator*(const
SmallMatrix<m,n>& f, const SmallMatrix<n,n1>& g){
...

so that if there is a class convertible to SmallMatrix it can use the
operator*


Thank you for your suggestions.
 
D

daniele lugli

And none of that adds anything.  I can do all that with the array.

Of course yes; and it's precisely what I don't want to do. I don't
like copying and pasting the same code many times.
With the risk of pasting the wrong lines and looping beyond the size
of the matrix, what is impossible with my class.
 In
fact, I'd be better off doing so since I'm not relying on silent
conversion operators to break encapsulation.

your opinion.
I have no reason to completely hide the data: accessing directly via []
[] is a simple and overhead-free way to fill or read the entries.

Then why not just leave the variable public?

Why should I write .M[][] when I can simply write [][] ?
an obviously misjudged
attempt to force [][] syntax into the equation.
Why 'attempt'? It works.

Does it?

Yes it does.
Examples please.

As with all classes that offer implicit conversion operators, your
conversion sequence will be used silently when perhaps it should not.

Are you able to show an example of this? Code, I mean, not words.
Reconsider your conversion operator and attempt to gain [][] syntax.
Maybe through an operator[] returning a row selector object, having in
turn an operator[] ?

Or, I don't know, a function?

Give your example code please.
Because you've measured it and know that it's a problem, right?

Yes, of course. Here is the code, running on Linux:

template<int m, int n>
class SmallMatrix
{
typedef double myData [m] [n];
myData M;

public:
SmallMatrix () {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
M[j] = 0.;
}
}
}
virtual ~SmallMatrix () {}
operator myData & () {
return M;
}
operator const myData & () const {
return M;
}
};

template<int m, int n>
class OtherSmallMatrix
{
typedef double myData [m] [n];
myData M;

//template<int m, int n>
class OtherSmallMatrixRowSelector
{
myData & data;
int row;
public:
OtherSmallMatrixRowSelector (OtherSmallMatrix & _osm, int
_row):
data (_osm.M), row (_row) {}
OtherSmallMatrixRowSelector (const
OtherSmallMatrixRowSelector & as):
data (as.data), row (as.row) {}
double & operator[] (int col) { return data[row][col]; }
};

public:
OtherSmallMatrix () {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
M[j] = 0.;
}
}
}
virtual ~OtherSmallMatrix () {}
OtherSmallMatrixRowSelector operator[] (int row) {
return OtherSmallMatrixRowSelector (*this, row);
}
};

#include <sys/time.h>
#include <sys/resource.h>
#include <iostream>

using namespace std;

int main () {

struct rusage before, after;
double diff;
const int repeat = 1000000;

SmallMatrix<2, 3> sm;
getrusage (RUSAGE_SELF, &before);
for (int k = 1; k <= repeat; k++) {
sm[1][1] = (double)k;
}
getrusage (RUSAGE_SELF, &after);
diff = (after.ru_utime.tv_sec - before.ru_utime.tv_sec) +
(after.ru_utime.tv_usec - before.ru_utime.tv_usec) * 1.e-6;
cout << "Time in seconds for " << repeat << " accesses to a
SmallMatrix element: "
<< diff << endl;

OtherSmallMatrix<2, 3> osm;
getrusage (RUSAGE_SELF, &before);
for (int k = 1; k <= repeat; k++) {
osm[1][1] = (double)k;
}
getrusage (RUSAGE_SELF, &after);
diff = (after.ru_utime.tv_sec - before.ru_utime.tv_sec) +
(after.ru_utime.tv_usec - before.ru_utime.tv_usec) * 1.e-6;
cout << "Time in seconds for " << repeat << " accesses to an
OtherSmallMatrix element: "
<< diff << endl;

}

and here are the results on my machine:

Time in seconds for 1000000 accesses to a SmallMatrix element: 0.004
Time in seconds for 1000000 accesses to an OtherSmallMatrix element:
0.008

Doubling the time could really be a problem.
 
N

Noah Roberts

Of course yes; and it's precisely what I don't want to do. I don't
like copying and pasting the same code many times.

Who said anything about copy/pasting code? You can write templates
that operate on arrays you know.
With the risk of pasting the wrong lines and looping beyond the size
of the matrix, what is impossible with my class.

Clearly not. Not even close. Your matrix class provides ZERO bounds
protection of any kind, which was my point.

 In
fact, I'd be better off doing so since I'm not relying on silent
conversion operators to break encapsulation.

your opinion.


 The encapsulation
benefit you'd normally get from implementing a matrix class is
entirely destroyed by your conversion operator,
I have no reason to completely hide the data: accessing directly via []
[] is a simple and overhead-free way to fill or read the entries.
Then why not just leave the variable public?

Why should I write .M[][] when I can simply write [][] ?

Why write anything at all? At this point I'm beginning to think we'd
all be better off if you didn't.
an obviously misjudged
attempt to force [][] syntax into the equation.
Why 'attempt'? It works.

Yes it does.

You mean it apparently does what you think you want it to to the best
of your understanding. You've not thought things through very well
though.
Are you able to show an example of this? Code, I mean, not words.

template <size_t n>
void fun(double [][n]);

fun(StupidMatrix());
Reconsider your conversion operator and attempt to gain [][] syntax..
Maybe through an operator[] returning a row selector object, having in
turn an operator[] ?
Or, I don't know, a function?

Give your example code please.


template < typename T, size_t M, size_t N >
struct slightly_better_matrix
{
T elem(size_t m, size_t n); // no unnecessary exposure of privates,
no complicated reference temps.

slightly_better_matrix() : mtx_() {} // no crazy for loop crap
either.
private:
T mtx_[M][N]; // doesn't have to be this.
};

I'd show you how to use expression templates to make * but It'd blow
your mind too much, especially since "use a function" required example
code.
and here are the results on my machine:

Time in seconds for 1000000 accesses to a SmallMatrix element: 0.004
Time in seconds for 1000000 accesses to an OtherSmallMatrix element:
0.008

Doubling the time could really be a problem.

Try turning off the -g switch and turning on some optimizations.
Examine the assembler output. G++ is actually quite good at inlining
things like this.

Furthermore you're missing a whole class of simpler solutions that
don't exhibit either issue and are prone to easier use and more reuse
of algorithms to a wider array of problems.
 
D

daniele lugli

Of course yes; and it's precisely what I don't want to do. I don't
like copying and pasting the same code many times.

Who said anything about copy/pasting code?  You can write templates
that operate on arrays you know.
With the risk of pasting the wrong lines and looping beyond the size
of the matrix, what is impossible with my class.

Clearly not.  Not even close.  Your matrix class provides ZERO bounds
protection of any kind, which was my point.

StupidMtx<1,1> digit;
double x = digit[99][4032]; // will happily compile.










your opinion.
 The encapsulation
benefit you'd normally get from implementing a matrix class is
entirely destroyed by your conversion operator,
I have no reason to completely hide the data: accessing directly via []
[] is a simple and overhead-free way to fill or read the entries.
Then why not just leave the variable public?
Why should I write .M[][] when I can simply write [][] ?

Why write anything at all?  At this point I'm beginning to think we'd
all be better off if you didn't.


an obviously misjudged
attempt to force [][] syntax into the equation.
Why 'attempt'? It works.

I'd show you how to use expression templates to make * but It'd blow
your mind too much, especially since "use a function" required example
code.

When one comes to insults, it means that he has no valid argument to
oppose. And by the way it is very easy to just say "I could".

On groups like this, one can find people looking for help or willing
to help; then one can also find (a minority I hope) of persons like
you, who only want to show everybody how clever they are.
This usually because they aren't able to get this acknowledgement in
their real lives. And often, here neither :)

I won't reply any more to your messages; just ignore them, if any. I
have no time to waste with you.
 
P

Paul

Who said anything about copy/pasting code?  You can write templates
that operate on arrays you know.


Clearly not.  Not even close.  Your matrix class provides ZERO bounds
protection of any kind, which was my point.
This is untrue becuase the dimensions are a template argument. Each
instance of this class is guaranteed to be m x n dimensions, and any
wrong assignments will be compile time errors i.e:

Matrix<3,3> m1;
Matrix<3,5> m2;
Matrix<2,6> m3;

m3= m1*m2; //compile error.
m3 should be a 3 x 5 matrix.

Also any attempts to multiply two incompatable matrices will be
automatically be checked at compile time. I think this its a pretty
neat little program.

StupidMtx<1,1> digit;
double x = digit[99][4032]; // will happily compile.
I don't see how this proves the Op's Matrix class has no bounds
checking. The bounds of the OP's matrix class are automatically
checked by the compiler as they are template arguments.
<snip>
 
G

Goran

Dear all,
this class:
template<int m, int n>
class SmallMatrix
{
        typedef double myData [m] [n];
        myData M;
public:
        SmallMatrix () {
                for (int i = 0; i < m; i++) {
                        for (int j = 0; j < n; j++) {
                                M[j]= 0.;
                        }
                }
        }
        virtual ~SmallMatrix () {}
        operator myData & () {
                return M;
        }
        operator const myData & () const {
                return M;
        }


This entire class of yours can be replaced by this single line of
code:
;

That's right, a noop.

Now I'll use it:

double matrix0[10][5] = {};

Your class offers nothing over this implementation.


Well... You need templates and operator overloading to allow e.g. a =
b*c, which is a rather clear, albeit unsaid, requirement. Simple math
notation is neat for this kind of work.

It's a pity you went down so hard on the question, thereby destroying
a chance to teach someone something, possibly alienating them from
here on the road. Bad day at the office, huh?

Goran.
 
N

Noah Roberts

On 29 Ago, 08:06, Noah Roberts <[email protected]> wrote:
When one comes to insults, it means that he has no valid argument to
oppose.

Pretty far from true actually. This is known as an ad homenem
argument, claiming I've been insulting (and I have) and thus my
argument is wrong. It simply does not follow, as can be seen if you
actually DID follow what I was saying.

Who started with the insulting behavior is a matter of perspective as
well. I've found your replies quite irritating and combative.
On groups like this, one can find people looking for help or willing
to help; then one can also find (a minority I hope) of persons like
you, who only want to show everybody how clever they are.

Unfortunately for you, I was trying to help but you've decided instead
to be a twit.
This usually because they aren't able to get this acknowledgement in
their real lives. And often, here neither :)

I get a lot of recognition for my abilities actually. In truth quite
well deserved.
I won't reply any more to your messages; just ignore them, if any. I
have no time to waste with you.

I feel exactly the same way. Some people, you just can't reach.
 
M

Mariangela Lugli

double (&operator[](int row))[n] { return M[row]; }

Interestingly VC++ does not accept:

double (&operator[](std::size_t row))[n] { return M[row]; }

but g++ does.  Maybe this is a bug in VC++?
My g++ 4.4.3 accepts

double (&operator[](int row))[n] { return M[row]; }

and

double (&operator[](unsigned int row))[n] { return M[row]; }

but not

double (&operator[](std::size_t row))[n] { return M[row]; }

complaining that

expected ')' before '(' token

size_t boils down to long unsigned int, which is accepted if written
explicitly.

Shuffling the deck a little bit:

typedef double Row [n];
Row & operator[] (long unsigned int row) { return M[row]; }

is accepted, while

Row & operator[] (size_t row) { return M[row]; }

is not.

Yes, it looks like a bug, but not of VC++ only.
 
M

Mariangela Lugli

I don't see how this proves the Op's Matrix class has no bounds
checking. The bounds of the OP's matrix class are automatically
checked by the compiler as they are template arguments.

There is of course no bound checking when accessing an element:
nothing is added, from this point of view, to the 'raw' double array.

But, as you say, there is an implicit bound checking with all matrix
operations.
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top