4

I am writing a kind of matrix-library, so I gave my matrix a operator +, using operator overloading. It looks something like this.

friend matrix<T, size_x, size_y>  operator + (const matrix<T, size_x, size_y> & Input_1, const matrix<T, size_x, size_y> & Input_2){
    matrix<T, size_x, size_y> Output;
        for (int i=0; i<size_x; i++){
            for (int j=0; j<size_y; j++){
                Output.value[i][j]=Input_1.value[i][j]+Input_2.value[i][j];
            }
        }
    return Output;
}       

As far, as I tested it, it works. Now I like to add the -, /, * operators too, they all work the same. Of course I can use copy, replace and paste. But this is bad for readability and maintainability. Is there a smarter solution and perhaps a concept, since I don't know the name of the concept to google it? I just found, how to overload a single operator.

Andre Kampling
  • 5,476
  • 2
  • 20
  • 47
Markus
  • 183
  • 1
  • 5
  • 3
    You want one single piece of nested for loop with call-back function for each of +, -, *, and / (though matrix multiplication sounds not the same nested loop as + and -). But you still need to separate the overloading. In account of the number of lines of code, compile time and run time optimisation (if any) I'll highly recommend copy and paste and modify. – Ken Cheung Aug 24 '17 at 08:15
  • 3
    I'd be a bit more careful with * and / 'working the same' as no one will be expecting that. Matrix multiplication doesn't work that way. – UKMonkey Aug 24 '17 at 08:18
  • @Ken Cheung. Thank you. You gave me a new point for my research. Greetings Markus – Markus Aug 24 '17 at 08:24
  • At least in my matrix library I just copy-pasta. It's easier to step through for debugging and clearer for maintenance. It's also a std::array, so functions like the above you can lose the inner loop. – Robinson Aug 24 '17 at 08:26
  • @UKMonkey. actually, it is not a matrix. It's just a kind of matrix. It's a pde-grid or a discretized 2d-function. – Markus Aug 24 '17 at 08:26

2 Answers2

11

You might use a template and a rvalue reference && (needed for a temporary lambda expression that is created when calling):

template <typename F>
friend matrix<T, size_x, size_y>  doBinOp(F&& f,
                                          const matrix<T, size_x, size_y> & Input_1,
                                          const matrix<T, size_x, size_y> & Input_2)
{
    matrix<T, size_x, size_y> Output;
    for (int i=0; i<size_x; i++) {
        for (int j=0; j<size_y; j++) {
            Output.value[i][j] = f(Input_1.value[i][j], Input_2.value[i][j]);
        }
    }
    return Output;
}

And then

friend matrix<T, size_x, size_y>  operator + (const matrix<T, size_x, size_y> & Input_1,
                                              const matrix<T, size_x, size_y> & Input_2)
{
    return doBinOp([](auto l, auto r) { return l + r; }, Input_1, Input_2);
}
Andre Kampling
  • 5,476
  • 2
  • 20
  • 47
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • I am not familiar with lambda expressions and rvalue reference &&. Thanks to you, I will try and learn it now. – Markus Aug 24 '17 at 08:47
  • It seems more appropriate to speak of a forwarding reference here, because this reference also has the ability to bind to lvalues. – Arne Vogel Aug 24 '17 at 10:47
0

Unfortunately, while the + and - on matrices works almost the same, the * and / of matrices works completely differently from + and - and also differently between them.

Considering that you could only unify two implementations out of four, I'd say to keep it simple (you replace two 7-lines functions with a 7-line template and two one liner functions).

It's great as a learning exercise, but... just don't.

Calin Ceteras
  • 206
  • 1
  • 4