0

I have implemented a matrix class using CRTP. For the matrix multiplication, I would like to use a friend operator*. The problem is that, according to this question and my own experience, I need to define the operator* inside the class to make it work.

This means, however, that I have to re-use the class template parameters in the definition, which gives access only to one of the three matrices involved in the computation. I cannot seem to provide friendship to the others.

Code example:

template<template<unsigned, unsigned> class Child, unsigned M, unsigned N>
class BaseMatrix
{
    // This works, but does not give access to rhs or to the return value
    template<unsigned L>
        friend Child<M, L> operator*(const BaseMatrix<Child, M, N>& lhs, const BaseMatrix<Child, N, L>& rhs)
    {
        Child<M, L> result;
        result.v = lhs.v + rhs.v; // demo, of course
        return result;
    }

    // This compiles, but does not do anything
    template<template<unsigned, unsigned> class Child2, unsigned M2, unsigned N2, unsigned L>
        friend Child2<M2, N2> operator*(const BaseMatrix<Child2, M2, L>&, const     BaseMatrix<Child2, L, N2>&);

    // This produces an ambiguous overload
    template<unsigned L>
        friend Child<M, N> operator*(const BaseMatrix<Child, M, L>& lhs, const     BaseMatrix<Child, L, N>& rhs);

    double v;
};

template<unsigned M, unsigned N>
class ChildMatrix : public BaseMatrix<ChildMatrix, M, N>
{

};


int main()
{
    ChildMatrix<3, 4> a;
    ChildMatrix<4, 5> b;
    ChildMatrix<3, 5> c = a * b;

    return 0;
}

How can I prevent the access violations to rhs.v and to result.v errors here?

Community
  • 1
  • 1
lytenyn
  • 819
  • 5
  • 21

1 Answers1

1

Don't use friend for this. A matrix class should expose its elements individually, and that is enough to do the multiplication from a regular (non-friend) function.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • well, yes, but the regular element access functions check the indices for out-of-bounds access, and I would like to avoid that here. Also, this should be possible somehow, right? – lytenyn Nov 22 '13 at 14:21
  • Just do what std::vector does: provide one accessor which checks bounds (std::vector::at()), and one which does not (`operator[]` in the vector case, but you'll need to use parentheses for multiple dimensions). – John Zwinck Nov 22 '13 at 14:23
  • why, yes, thank you, that is a good idea. Nevertheless, it would be interesting to see the answer to my question, if it exists! – lytenyn Nov 22 '13 at 14:29