#include <iostream>
#include <algorithm>

class Matrix4 {
   float* m;
public:
   Matrix4() : m(new float[16]) {}
   Matrix4(const Matrix4& other)  : m(new float[16]) 
   { std::copy(other.m, other.m+16, m); std::cout << "\ncopy"; }
   Matrix4(Matrix4&& other) : m(other.m) { other.m = 0; std::cout << "\nmove"; }
   ~Matrix4() { delete[] m; }
   Matrix4& operator+= (const Matrix4& other) 
   { 
      for(auto i = 0; i < 16; ++i) { m[i] += other.m[i]; }
      return *this;
   }
};

Matrix4 operator+ (Matrix4 l /* move from temporary*/, const Matrix4& r) 
{ 
   std::cout << "\noperator+(Matrix4, const Matrix4&)";
   return std::move(l += r); // move explicitly, because += returns lvalue reference
}

Matrix4 operator+ (const Matrix4& l, Matrix4&& r) 
{ 
   std::cout << "\nnoperator+(const Matrix4&, Matrix4&&)";
   return std::move(r += l); // move explicitly
}

int main()
{
   Matrix4 a;
   std::cout << "\nMatrix4 b(a+a)";
   Matrix4 b(a+a);
   std::cout << "\nMatrix4 c(a + a + a)";
   Matrix4 c(a + a + a);
   std::cout << "\nMatrix4 d(a + (a + a))";
   Matrix4 d(a + (a + a));
}