diff --git a/dlib/matrix/matrix_math_functions.h b/dlib/matrix/matrix_math_functions.h
index 8f7f67fe9405032c930b6f2928fb7c74d6e54ede..15546bc0d7ef550307232007d8ed837081cf81f2 100644
--- a/dlib/matrix/matrix_math_functions.h
+++ b/dlib/matrix/matrix_math_functions.h
@@ -16,19 +16,20 @@ namespace dlib
 
 // ----------------------------------------------------------------------------------------
 
-#define DLIB_MATRIX_SIMPLE_STD_FUNCTION(name)  template <typename EXP>         \
-    struct op_##name : has_nondestructive_aliasing, preserves_dimensions<EXP>   \
+#define DLIB_MATRIX_SIMPLE_STD_FUNCTION(name) struct op_##name {                \
+    template <typename EXP>                                                     \
+    struct op : has_nondestructive_aliasing, preserves_dimensions<EXP>          \
     {                                                                           \
         typedef typename EXP::type type;                                        \
         template <typename M>                                                   \
         static type apply ( const M& m, long r, long c)                         \
         { return static_cast<type>(std::name(m(r,c))); }                        \
-    };                                                                          \
+    };};                                                                        \
     template < typename EXP >                                                   \
-    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_##name<EXP> > > name ( \
+    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_##name> > name (       \
         const matrix_exp<EXP>& m)                                               \
     {                                                                           \
-        typedef matrix_unary_exp<matrix_exp<EXP>,op_##name<EXP> > exp;          \
+        typedef matrix_unary_exp<matrix_exp<EXP>,op_##name> exp;                \
         return matrix_exp<exp>(exp(m));                                         \
     }                                                                           
 
@@ -57,51 +58,57 @@ DLIB_MATRIX_SIMPLE_STD_FUNCTION(atan)
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP>
-    struct op_sigmoid : has_nondestructive_aliasing, preserves_dimensions<EXP>
+    struct op_sigmoid 
     {
-        typedef typename EXP::type type;
-        template <typename M>
-        static type apply ( const M& m, long r, long c)
-        { 
-            const double e = 2.718281828459045235360287471352; 
-            double temp = std::pow(e,-m(r,c));
-            return static_cast<type>(1.0/(1.0 + temp));
-        }
+        template <typename EXP>
+        struct op : has_nondestructive_aliasing, preserves_dimensions<EXP>
+        {
+            typedef typename EXP::type type;
+            template <typename M>
+            static type apply ( const M& m, long r, long c)
+            { 
+                const double e = 2.718281828459045235360287471352; 
+                double temp = std::pow(e,-m(r,c));
+                return static_cast<type>(1.0/(1.0 + temp));
+            }
+        };
     };
 
     template <
         typename EXP
         >
-    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_sigmoid<EXP> > > sigmoid (
+    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_sigmoid> > sigmoid (
         const matrix_exp<EXP>& m
     )
     {
-        typedef matrix_unary_exp<matrix_exp<EXP>,op_sigmoid<EXP> > exp;
+        typedef matrix_unary_exp<matrix_exp<EXP>,op_sigmoid> exp;
         return matrix_exp<exp>(exp(m));
     }
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP>
-    struct op_round_zeros : has_nondestructive_aliasing, preserves_dimensions<EXP>
+    struct op_round_zeros 
     {
-        typedef typename EXP::type type;
-        template <typename M, typename T>
-        static type apply ( const M& m, const T& eps, long r, long c)
-        { 
-            const type temp = m(r,c);
-            if (temp >= eps || temp <= -eps)
-                return temp;
-            else
-                return 0;
-        }
+        template <typename EXP>
+        struct op : has_nondestructive_aliasing, preserves_dimensions<EXP>
+        {
+            typedef typename EXP::type type;
+            template <typename M, typename T>
+            static type apply ( const M& m, const T& eps, long r, long c)
+            { 
+                const type temp = m(r,c);
+                if (temp >= eps || temp <= -eps)
+                    return temp;
+                else
+                    return 0;
+            }
+        };
     };
 
     template <
         typename EXP
         >
-    const matrix_exp<matrix_scalar_binary_exp<matrix_exp<EXP>,typename EXP::type,op_round_zeros<EXP> > > round_zeros (
+    const matrix_exp<matrix_scalar_binary_exp<matrix_exp<EXP>,typename EXP::type,op_round_zeros> > round_zeros (
         const matrix_exp<EXP>& m
     )
     {
@@ -111,14 +118,14 @@ DLIB_MATRIX_SIMPLE_STD_FUNCTION(atan)
                 is_same_type<typename EXP::type,double>::value == true || 
                 is_same_type<typename EXP::type,long double>::value == true 
         ));
-        typedef matrix_scalar_binary_exp<matrix_exp<EXP>,typename EXP::type, op_round_zeros<EXP> > exp;
+        typedef matrix_scalar_binary_exp<matrix_exp<EXP>,typename EXP::type, op_round_zeros> exp;
         return matrix_exp<exp>(exp(m,10*std::numeric_limits<typename EXP::type>::epsilon()));
     }
 
     template <
         typename EXP
         >
-    const matrix_exp<matrix_scalar_binary_exp<matrix_exp<EXP>,typename EXP::type,op_round_zeros<EXP> > > round_zeros (
+    const matrix_exp<matrix_scalar_binary_exp<matrix_exp<EXP>,typename EXP::type,op_round_zeros> > round_zeros (
         const matrix_exp<EXP>& m,
         typename EXP::type eps 
     )
@@ -129,70 +136,79 @@ DLIB_MATRIX_SIMPLE_STD_FUNCTION(atan)
                 is_same_type<typename EXP::type,double>::value == true || 
                 is_same_type<typename EXP::type,long double>::value == true 
         ));
-        typedef matrix_scalar_binary_exp<matrix_exp<EXP>,typename EXP::type, op_round_zeros<EXP> > exp;
+        typedef matrix_scalar_binary_exp<matrix_exp<EXP>,typename EXP::type, op_round_zeros> exp;
         return matrix_exp<exp>(exp(m,eps));
     }
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP>
-    struct op_cubed : has_nondestructive_aliasing, preserves_dimensions<EXP>
+    struct op_cubed 
     {
-        typedef typename EXP::type type;
-        template <typename M>
-        static type apply ( const M& m, long r, long c)
-        { return m(r,c)*m(r,c)*m(r,c); }
+        template <typename EXP>
+        struct op : has_nondestructive_aliasing, preserves_dimensions<EXP>
+        {
+            typedef typename EXP::type type;
+            template <typename M>
+            static type apply ( const M& m, long r, long c)
+            { return m(r,c)*m(r,c)*m(r,c); }
+        };
     };
 
     template <
         typename EXP
         >
-    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_cubed<EXP> > > cubed (
+    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_cubed> > cubed (
         const matrix_exp<EXP>& m
     )
     {
-        typedef matrix_unary_exp<matrix_exp<EXP>,op_cubed<EXP> > exp;
+        typedef matrix_unary_exp<matrix_exp<EXP>,op_cubed> exp;
         return matrix_exp<exp>(exp(m));
     }
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP>
-    struct op_squared : has_nondestructive_aliasing, preserves_dimensions<EXP>
+    struct op_squared
     {
-        typedef typename EXP::type type;
-        template <typename M>
-        static type apply ( const M& m, long r, long c)
-        { return m(r,c)*m(r,c); }
+        template <typename EXP>
+        struct op : has_nondestructive_aliasing, preserves_dimensions<EXP>
+        {
+            typedef typename EXP::type type;
+            template <typename M>
+            static type apply ( const M& m, long r, long c)
+            { return m(r,c)*m(r,c); }
+        };
     };
 
     template <
         typename EXP
         >
-    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_squared<EXP> > > squared (
+    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_squared> > squared (
         const matrix_exp<EXP>& m
     )
     {
-        typedef matrix_unary_exp<matrix_exp<EXP>,op_squared<EXP> > exp;
+        typedef matrix_unary_exp<matrix_exp<EXP>,op_squared> exp;
         return matrix_exp<exp>(exp(m));
     }
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP>
-    struct op_pow : has_nondestructive_aliasing, preserves_dimensions<EXP>
+    struct op_pow
     {
-        typedef typename EXP::type type;
-        template <typename M, typename S>
-        static type apply ( const M& m, const S& s, long r, long c)
-        { return static_cast<type>(std::pow(m(r,c),s)); }
+        template <typename EXP>
+        struct op : has_nondestructive_aliasing, preserves_dimensions<EXP>
+        {
+            typedef typename EXP::type type;
+            template <typename M, typename S>
+            static type apply ( const M& m, const S& s, long r, long c)
+            { return static_cast<type>(std::pow(m(r,c),s)); }
+        };
     };
 
     template <
         typename EXP,
         typename S
         >
-    const matrix_exp<matrix_scalar_binary_exp<matrix_exp<EXP>,typename EXP::type,op_pow<EXP> > > pow (
+    const matrix_exp<matrix_scalar_binary_exp<matrix_exp<EXP>,typename EXP::type,op_pow> > pow (
         const matrix_exp<EXP>& m,
         const S& s
     )
@@ -203,31 +219,34 @@ DLIB_MATRIX_SIMPLE_STD_FUNCTION(atan)
                 is_same_type<typename EXP::type,double>::value == true || 
                 is_same_type<typename EXP::type,long double>::value == true 
         ));
-        typedef matrix_scalar_binary_exp<matrix_exp<EXP>,typename EXP::type,op_pow<EXP> > exp;
+        typedef matrix_scalar_binary_exp<matrix_exp<EXP>,typename EXP::type,op_pow> exp;
         return matrix_exp<exp>(exp(m,s));
     }
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP>
-    struct op_reciprocal : has_nondestructive_aliasing, preserves_dimensions<EXP>
+    struct op_reciprocal
     {
-        typedef typename EXP::type type;
-        template <typename M>
-        static type apply ( const M& m, long r, long c)
-        { 
-            const type temp = m(r,c);
-            if (temp != 0)
-                return static_cast<type>(1.0/temp);
-            else
-                return 0;
-        }
+        template <typename EXP>
+        struct op : has_nondestructive_aliasing, preserves_dimensions<EXP>
+        {
+            typedef typename EXP::type type;
+            template <typename M>
+            static type apply ( const M& m, long r, long c)
+            { 
+                const type temp = m(r,c);
+                if (temp != 0)
+                    return static_cast<type>(1.0/temp);
+                else
+                    return 0;
+            }
+        };
     };
 
     template <
         typename EXP
         >
-    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_reciprocal<EXP> > > reciprocal (
+    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_reciprocal> > reciprocal (
         const matrix_exp<EXP>& m
     )
     {
@@ -237,27 +256,30 @@ DLIB_MATRIX_SIMPLE_STD_FUNCTION(atan)
                 is_same_type<typename EXP::type,double>::value == true || 
                 is_same_type<typename EXP::type,long double>::value == true 
         ));
-        typedef matrix_unary_exp<matrix_exp<EXP>,op_reciprocal<EXP> > exp;
+        typedef matrix_unary_exp<matrix_exp<EXP>,op_reciprocal> exp;
         return matrix_exp<exp>(exp(m));
     }
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP>
-    struct op_normalize : has_nondestructive_aliasing, preserves_dimensions<EXP>
+    struct op_normalize
     {
-        typedef typename EXP::type type;
-        template <typename M>
-        static type apply ( const M& m, const type& s, long r, long c)
-        { 
-            return m(r,c)*s;
-        }
+        template <typename EXP>
+        struct op : has_nondestructive_aliasing, preserves_dimensions<EXP>
+        {
+            typedef typename EXP::type type;
+            template <typename M>
+            static type apply ( const M& m, const type& s, long r, long c)
+            { 
+                return m(r,c)*s;
+            }
+        };
     };
 
     template <
         typename EXP
         >
-    const matrix_exp<matrix_scalar_binary_exp<matrix_exp<EXP>,typename EXP::type,op_normalize<EXP> > > normalize (
+    const matrix_exp<matrix_scalar_binary_exp<matrix_exp<EXP>,typename EXP::type,op_normalize> > normalize (
         const matrix_exp<EXP>& m
     )
     {
@@ -267,7 +289,7 @@ DLIB_MATRIX_SIMPLE_STD_FUNCTION(atan)
                 is_same_type<typename EXP::type,double>::value == true || 
                 is_same_type<typename EXP::type,long double>::value == true 
         ));
-        typedef matrix_scalar_binary_exp<matrix_exp<EXP>,typename EXP::type, op_normalize<EXP> > exp;
+        typedef matrix_scalar_binary_exp<matrix_exp<EXP>,typename EXP::type, op_normalize> exp;
 
         typename EXP::type temp = std::sqrt(sum(squared(m)));
         if (temp != 0.0)
@@ -278,21 +300,24 @@ DLIB_MATRIX_SIMPLE_STD_FUNCTION(atan)
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP>
-    struct op_round : has_nondestructive_aliasing, preserves_dimensions<EXP>
+    struct op_round
     {
-        typedef typename EXP::type type;
-        template <typename M>
-        static type apply ( const M& m, long r, long c)
-        { 
-            return static_cast<type>(std::floor(m(r,c)+0.5)); 
-        }
+        template <typename EXP>
+        struct op : has_nondestructive_aliasing, preserves_dimensions<EXP>
+        {
+            typedef typename EXP::type type;
+            template <typename M>
+            static type apply ( const M& m, long r, long c)
+            { 
+                return static_cast<type>(std::floor(m(r,c)+0.5)); 
+            }
+        };
     };
 
     template <
         typename EXP
         >
-    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_round<EXP> > > round (
+    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_round> > round (
         const matrix_exp<EXP>& m
     )
     {
@@ -302,27 +327,30 @@ DLIB_MATRIX_SIMPLE_STD_FUNCTION(atan)
                 is_same_type<typename EXP::type,double>::value == true || 
                 is_same_type<typename EXP::type,long double>::value == true 
         ));
-        typedef matrix_unary_exp<matrix_exp<EXP>,op_round<EXP> > exp;
+        typedef matrix_unary_exp<matrix_exp<EXP>,op_round> exp;
         return matrix_exp<exp>(exp(m));
     }
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP1, typename EXP2>
-    struct op_complex_matrix : has_nondestructive_aliasing, preserves_dimensions<EXP1,EXP2>
+    struct op_complex_matrix
     {
-        typedef std::complex<typename EXP1::type> type;
-
-        template <typename M1, typename M2>
-        static type apply ( const M1& m1, const M2& m2 , long r, long c)
-        { return type(m1(r,c),m2(r,c)); }
+        template <typename EXP1, typename EXP2>
+        struct op : has_nondestructive_aliasing, preserves_dimensions<EXP1,EXP2>
+        {
+            typedef std::complex<typename EXP1::type> type;
+
+            template <typename M1, typename M2>
+            static type apply ( const M1& m1, const M2& m2 , long r, long c)
+            { return type(m1(r,c),m2(r,c)); }
+        };
     };
 
     template <
         typename EXP1,
         typename EXP2
         >
-    const matrix_exp<matrix_binary_exp<matrix_exp<EXP1>,matrix_exp<EXP2>,op_complex_matrix<EXP1,EXP2> > > complex_matrix (
+    const matrix_exp<matrix_binary_exp<matrix_exp<EXP1>,matrix_exp<EXP2>,op_complex_matrix> > complex_matrix (
         const matrix_exp<EXP1>& real_part,
         const matrix_exp<EXP2>& imag_part 
     )
@@ -340,73 +368,82 @@ DLIB_MATRIX_SIMPLE_STD_FUNCTION(atan)
             << "\n\timag_part.nr(): " << imag_part.nr()
             << "\n\timag_part.nc(): " << imag_part.nc() 
             );
-        typedef matrix_binary_exp<matrix_exp<EXP1>,matrix_exp<EXP2>,op_complex_matrix<EXP1,EXP2> > exp;
+        typedef matrix_binary_exp<matrix_exp<EXP1>,matrix_exp<EXP2>,op_complex_matrix> exp;
         return matrix_exp<exp>(exp(real_part,imag_part));
     }
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP>
-    struct op_norm : has_nondestructive_aliasing, preserves_dimensions<EXP>
+    struct op_norm
     {
-        typedef typename EXP::type::value_type type;
-        template <typename M>
-        static type apply ( const M& m, long r, long c)
-        { return std::norm(m(r,c)); }
+        template <typename EXP>
+        struct op : has_nondestructive_aliasing, preserves_dimensions<EXP>
+        {
+            typedef typename EXP::type::value_type type;
+            template <typename M>
+            static type apply ( const M& m, long r, long c)
+            { return std::norm(m(r,c)); }
+        };
     };
 
     template <
         typename EXP
         >
-    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_norm<EXP> > > norm (
+    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_norm> > norm (
         const matrix_exp<EXP>& m
     )
     {
-        typedef matrix_unary_exp<matrix_exp<EXP>,op_norm<EXP> > exp;
+        typedef matrix_unary_exp<matrix_exp<EXP>,op_norm> exp;
         return matrix_exp<exp>(exp(m));
     }
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP>
-    struct op_real : has_nondestructive_aliasing, preserves_dimensions<EXP>
+    struct op_real
     {
-        typedef typename EXP::type::value_type type;
-        template <typename M>
-        static type apply ( const M& m, long r, long c)
-        { return std::real(m(r,c)); }
+        template <typename EXP>
+        struct op : has_nondestructive_aliasing, preserves_dimensions<EXP>
+        {
+            typedef typename EXP::type::value_type type;
+            template <typename M>
+            static type apply ( const M& m, long r, long c)
+            { return std::real(m(r,c)); }
+        };
     };
 
     template <
         typename EXP
         >
-    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_real<EXP> > > real (
+    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_real> > real (
         const matrix_exp<EXP>& m
     )
     {
-        typedef matrix_unary_exp<matrix_exp<EXP>,op_real<EXP> > exp;
+        typedef matrix_unary_exp<matrix_exp<EXP>,op_real> exp;
         return matrix_exp<exp>(exp(m));
     }
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP>
-    struct op_imag : has_nondestructive_aliasing, preserves_dimensions<EXP>
+    struct op_imag
     {
-        typedef typename EXP::type::value_type type;
-        template <typename M>
-        static type apply ( const M& m, long r, long c)
-        { return std::imag(m(r,c)); }
+        template <typename EXP>
+        struct op : has_nondestructive_aliasing, preserves_dimensions<EXP>
+        {
+            typedef typename EXP::type::value_type type;
+            template <typename M>
+            static type apply ( const M& m, long r, long c)
+            { return std::imag(m(r,c)); }
+        };
     };
 
     template <
         typename EXP
         >
-    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_imag<EXP> > > imag (
+    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_imag> > imag (
         const matrix_exp<EXP>& m
     )
     {
-        typedef matrix_unary_exp<matrix_exp<EXP>,op_imag<EXP> > exp;
+        typedef matrix_unary_exp<matrix_exp<EXP>,op_imag> exp;
         return matrix_exp<exp>(exp(m));
     }
 
diff --git a/dlib/matrix/matrix_utilities.h b/dlib/matrix/matrix_utilities.h
index 8e7c3f774796f9864c6212138e11a1f2c89c2799..f2c91baedafb149def042e6c6e3436d3e55dd37c 100644
--- a/dlib/matrix/matrix_utilities.h
+++ b/dlib/matrix/matrix_utilities.h
@@ -895,7 +895,7 @@ namespace dlib
 
     template <
         typename M,
-        typename OP
+        typename OP_
         >
     class matrix_unary_exp  
     {
@@ -904,6 +904,8 @@ namespace dlib
                 - must be a matrix_exp or matrix_ref object (or
                   an object with a compatible interface).
         !*/
+        typedef typename OP_::template op<M> OP;
+
     public:
         typedef typename OP::type type;
         typedef matrix_unary_exp ref_type;
@@ -1179,7 +1181,7 @@ namespace dlib
     template <
         typename M,
         typename S,
-        typename OP
+        typename OP_
         >
     class matrix_scalar_binary_exp  
     {
@@ -1188,6 +1190,8 @@ namespace dlib
                 - must be a matrix_exp or matrix_ref object (or
                   an object with a compatible interface).
         !*/
+        typedef typename OP_::template op<M> OP;
+
     public:
         typedef typename OP::type type;
         typedef matrix_scalar_binary_exp ref_type;
@@ -1240,7 +1244,7 @@ namespace dlib
     template <
         typename M1,
         typename M2,
-        typename OP
+        typename OP_
         >
     class matrix_binary_exp  
     {
@@ -1249,6 +1253,8 @@ namespace dlib
                 - must be a matrix_exp or matrix_ref object (or
                   an object with a compatible interface).
         !*/
+        typedef typename OP_::template op<M1,M2> OP;
+
     public:
         typedef typename OP::type type;
         typedef matrix_binary_exp ref_type;
@@ -1743,66 +1749,73 @@ namespace dlib
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP>
-    struct op_trans : has_destructive_aliasing
+    struct op_trans 
     {
-        const static long NR = EXP::NC;
-        const static long NC = EXP::NR;
-        typedef typename EXP::type type;
-        typedef typename EXP::mem_manager_type mem_manager_type;
-        template <typename M>
-        static type apply ( const M& m, long r, long c)
-        { return m(c,r); }
-
-        template <typename M>
-        static long nr (const M& m) { return m.nc(); }
-        template <typename M>
-        static long nc (const M& m) { return m.nr(); }
+        template <typename EXP>
+        struct op : has_destructive_aliasing
+        {
+            const static long NR = EXP::NC;
+            const static long NC = EXP::NR;
+            typedef typename EXP::type type;
+            typedef typename EXP::mem_manager_type mem_manager_type;
+            template <typename M>
+            static type apply ( const M& m, long r, long c)
+            { return m(c,r); }
+
+            template <typename M>
+            static long nr (const M& m) { return m.nc(); }
+            template <typename M>
+            static long nc (const M& m) { return m.nr(); }
+        }; 
     };
 
     template <
         typename EXP
         >
-    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_trans<EXP> > > trans (
+    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_trans> > trans (
         const matrix_exp<EXP>& m
     )
     {
-        typedef matrix_unary_exp<matrix_exp<EXP>,op_trans<EXP> > exp;
+        typedef matrix_unary_exp<matrix_exp<EXP>,op_trans> exp;
         return matrix_exp<exp>(exp(m));
     }
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP, long R, long C>
-    struct op_removerc : has_destructive_aliasing
+    template <long R, long C>
+    struct op_removerc
     {
-        const static long NR = EXP::NR - 1;
-        const static long NC = EXP::NC - 1;
-        typedef typename EXP::type type;
-        typedef typename EXP::mem_manager_type mem_manager_type;
-        template <typename M>
-        static type apply ( const M& m, long r, long c)
-        { 
-            if (r < R)
-            {
-                if (c < C)
-                    return m(r,c); 
-                else
-                    return m(r,c+1); 
-            }
-            else
-            {
-                if (c < C)
-                    return m(r+1,c); 
+        template <typename EXP>
+        struct op : has_destructive_aliasing
+        {
+            const static long NR = EXP::NR - 1;
+            const static long NC = EXP::NC - 1;
+            typedef typename EXP::type type;
+            typedef typename EXP::mem_manager_type mem_manager_type;
+            template <typename M>
+            static type apply ( const M& m, long r, long c)
+            { 
+                if (r < R)
+                {
+                    if (c < C)
+                        return m(r,c); 
+                    else
+                        return m(r,c+1); 
+                }
                 else
-                    return m(r+1,c+1); 
+                {
+                    if (c < C)
+                        return m(r+1,c); 
+                    else
+                        return m(r+1,c+1); 
+                }
             }
-        }
 
-        template <typename M>
-        static long nr (const M& m) { return m.nr() - 1; }
-        template <typename M>
-        static long nc (const M& m) { return m.nc() - 1; }
+            template <typename M>
+            static long nr (const M& m) { return m.nr() - 1; }
+            template <typename M>
+            static long nc (const M& m) { return m.nc() - 1; }
+        };
     };
 
     template <
@@ -1810,7 +1823,7 @@ namespace dlib
         long C,
         typename EXP
         >
-    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_removerc<EXP,R,C> > > removerc (
+    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_removerc<R,C> > > removerc (
         const matrix_exp<EXP>& m
     )
     {
@@ -1826,33 +1839,36 @@ namespace dlib
             << "\n\tR:      " << R 
             << "\n\tC:      " << C 
             );
-        typedef matrix_unary_exp<matrix_exp<EXP>,op_removerc<EXP,R,C> > exp;
+        typedef matrix_unary_exp<matrix_exp<EXP>,op_removerc<R,C> > exp;
         return matrix_exp<exp>(exp(m));
     }
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP>
-    struct op_diag : has_destructive_aliasing
+    struct op_diag
     {
-        const static long NR = EXP::NC;
-        const static long NC = 1;
-        typedef typename EXP::type type;
-        typedef typename EXP::mem_manager_type mem_manager_type;
-        template <typename M>
-        static type apply ( const M& m, long r, long c)
-        { return m(r,r); }
-
-        template <typename M>
-        static long nr (const M& m) { return m.nr(); }
-        template <typename M>
-        static long nc (const M& m) { return 1; }
+        template <typename EXP>
+        struct op : has_destructive_aliasing
+        {
+            const static long NR = EXP::NC;
+            const static long NC = 1;
+            typedef typename EXP::type type;
+            typedef typename EXP::mem_manager_type mem_manager_type;
+            template <typename M>
+            static type apply ( const M& m, long r, long c)
+            { return m(r,r); }
+
+            template <typename M>
+            static long nr (const M& m) { return m.nr(); }
+            template <typename M>
+            static long nc (const M& m) { return 1; }
+        };
     };
 
     template <
         typename EXP
         >
-    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_diag<EXP> > > diag (
+    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_diag> > diag (
         const matrix_exp<EXP>& m
     )
     {
@@ -1864,30 +1880,34 @@ namespace dlib
             << "\n\tm.nr(): " << m.nr()
             << "\n\tm.nc(): " << m.nc() 
             );
-        typedef matrix_unary_exp<matrix_exp<EXP>,op_diag<EXP> > exp;
+        typedef matrix_unary_exp<matrix_exp<EXP>,op_diag> exp;
         return matrix_exp<exp>(exp(m));
     }
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP, typename target_type>
-    struct op_cast : has_nondestructive_aliasing, preserves_dimensions<EXP>
+    template <typename target_type>
+    struct op_cast
     {
-        typedef target_type type;
-        template <typename M>
-        static type apply ( const M& m, long r, long c)
-        { return static_cast<target_type>(m(r,c)); }
+        template <typename EXP>
+        struct op : has_nondestructive_aliasing, preserves_dimensions<EXP>
+        {
+            typedef target_type type;
+            template <typename M>
+            static type apply ( const M& m, long r, long c)
+            { return static_cast<target_type>(m(r,c)); }
+        };
     };
 
     template <
         typename target_type,
         typename EXP
         >
-    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_cast<EXP,target_type> > > matrix_cast (
+    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_cast<target_type> > > matrix_cast (
         const matrix_exp<EXP>& m
     )
     {
-        typedef matrix_unary_exp<matrix_exp<EXP>,op_cast<EXP,target_type> > exp;
+        typedef matrix_unary_exp<matrix_exp<EXP>,op_cast<target_type> > exp;
         return matrix_exp<exp>(exp(m));
     }
 
@@ -2740,13 +2760,17 @@ namespace dlib
 
 // ----------------------------------------------------------------------------------------
 
-    template <long R, long C, typename EXP>
-    struct op_rotate : has_destructive_aliasing, preserves_dimensions<EXP>
+    template <long R, long C>
+    struct op_rotate
     {
-        typedef typename EXP::type type;
-        template <typename M>
-        static type apply ( const M& m, long r, long c)
-        { return m((r+R)%m.nr(),(c+C)%m.nc()); }
+        template <typename EXP>
+        struct op : has_destructive_aliasing, preserves_dimensions<EXP>
+        {
+            typedef typename EXP::type type;
+            template <typename M>
+            static type apply ( const M& m, long r, long c)
+            { return m((r+R)%m.nr(),(c+C)%m.nc()); }
+        };
     };
 
     template <
@@ -2754,7 +2778,7 @@ namespace dlib
         long C,
         typename EXP
         >
-    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_rotate<R,C,EXP> > > rotate (
+    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_rotate<R,C> > > rotate (
         const matrix_exp<EXP>& m
     )
     {
@@ -2770,27 +2794,30 @@ namespace dlib
             << "\n\tR:      " << R 
             << "\n\tC:      " << C 
             );
-        typedef matrix_unary_exp<matrix_exp<EXP>,op_rotate<R,C,EXP> > exp;
+        typedef matrix_unary_exp<matrix_exp<EXP>,op_rotate<R,C> > exp;
         return matrix_exp<exp>(exp(m));
     }
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP1, typename EXP2, typename EXP3 = void, typename EXP4 = void>
-    struct op_pointwise_multiply : public has_nondestructive_aliasing, public preserves_dimensions<EXP1,EXP2,EXP3,EXP4>
+    struct op_pointwise_multiply
     {
-        typedef typename EXP1::type type;
+        template <typename EXP1, typename EXP2>
+        struct op : public has_nondestructive_aliasing, public preserves_dimensions<EXP1,EXP2>
+        {
+            typedef typename EXP1::type type;
 
-        template <typename M1, typename M2>
-        static type apply ( const M1& m1, const M2& m2 , long r, long c)
-        { return m1(r,c)*m2(r,c); }
+            template <typename M1, typename M2>
+            static type apply ( const M1& m1, const M2& m2 , long r, long c)
+            { return m1(r,c)*m2(r,c); }
+        };
     };
 
     template <
         typename EXP1,
         typename EXP2
         >
-    inline const matrix_exp<matrix_binary_exp<matrix_exp<EXP1>,matrix_exp<EXP2>,op_pointwise_multiply<EXP1,EXP2> > > pointwise_multiply (
+    inline const matrix_exp<matrix_binary_exp<EXP1,EXP2,op_pointwise_multiply> > pointwise_multiply (
         const matrix_exp<EXP1>& a,
         const matrix_exp<EXP2>& b 
     )
@@ -2807,8 +2834,8 @@ namespace dlib
             << "\n\tb.nr(): " << b.nr()
             << "\n\tb.nc(): " << b.nc() 
             );
-        typedef matrix_binary_exp<matrix_exp<EXP1>,matrix_exp<EXP2>,op_pointwise_multiply<EXP1,EXP2> > exp;
-        return matrix_exp<exp>(exp(a,b));
+        typedef matrix_binary_exp<EXP1,EXP2,op_pointwise_multiply> exp;
+        return matrix_exp<exp>(exp(a.ref(),b.ref()));
     }
 
     template <
@@ -2816,9 +2843,7 @@ namespace dlib
         typename EXP2,
         typename EXP3
         >
-    inline const matrix_exp<
-        matrix_binary_exp< matrix_binary_exp<matrix_exp<EXP1>,matrix_exp<EXP2>,op_pointwise_multiply<EXP1,EXP2> > ,
-                          matrix_exp<EXP3>, op_pointwise_multiply<EXP1,EXP2,EXP3> > >
+    inline const matrix_exp<matrix_binary_exp<matrix_binary_exp<EXP1,EXP2,op_pointwise_multiply>,EXP3,op_pointwise_multiply> >
         pointwise_multiply (
         const matrix_exp<EXP1>& a,
         const matrix_exp<EXP2>& b, 
@@ -2843,10 +2868,10 @@ namespace dlib
             << "\n\tc.nr(): " << c.nr()
             << "\n\tc.nc(): " << c.nc() 
             );
-        typedef  matrix_binary_exp<matrix_exp<EXP1>,matrix_exp<EXP2>,op_pointwise_multiply<EXP1,EXP2> > exp; 
-        typedef matrix_binary_exp< exp , matrix_exp<EXP3>, op_pointwise_multiply<EXP1,EXP2,EXP3> > exp2;
+        typedef matrix_binary_exp<EXP1,EXP2,op_pointwise_multiply> exp; 
+        typedef matrix_binary_exp<exp , EXP3, op_pointwise_multiply> exp2;
 
-        return matrix_exp<exp2>(exp2(exp(a,b),c));
+        return matrix_exp<exp2>(exp2(exp(a.ref(),b.ref()),c.ref()));
     }
 
     template <
@@ -2856,9 +2881,9 @@ namespace dlib
         typename EXP4
         >
     inline const matrix_exp<
-        matrix_binary_exp< matrix_binary_exp<matrix_exp<EXP1>,matrix_exp<EXP2>,op_pointwise_multiply<EXP1,EXP2> > ,
-                          matrix_binary_exp<matrix_exp<EXP3>,matrix_exp<EXP4>,op_pointwise_multiply<EXP3,EXP4> >, 
-                          op_pointwise_multiply<EXP1,EXP2,EXP3,EXP4> > >
+        matrix_binary_exp<matrix_binary_exp<EXP1,EXP2,op_pointwise_multiply> ,
+                          matrix_binary_exp<EXP3,EXP4,op_pointwise_multiply>, 
+                          op_pointwise_multiply> >
         pointwise_multiply (
         const matrix_exp<EXP1>& a,
         const matrix_exp<EXP2>& b, 
@@ -2890,11 +2915,11 @@ namespace dlib
             << "\n\td.nr(): " << d.nr()
             << "\n\td.nc(): " << d.nc() 
             );
-        typedef matrix_binary_exp<matrix_exp<EXP1>,matrix_exp<EXP2>,op_pointwise_multiply<EXP1,EXP2> > exp1;
-        typedef matrix_binary_exp<matrix_exp<EXP3>,matrix_exp<EXP4>,op_pointwise_multiply<EXP3,EXP4> > exp2;
+        typedef matrix_binary_exp<EXP1,EXP2,op_pointwise_multiply> exp1;
+        typedef matrix_binary_exp<EXP3,EXP4,op_pointwise_multiply> exp2;
 
-        typedef matrix_binary_exp<  exp1  ,  exp2, op_pointwise_multiply<EXP1,EXP2,EXP3,EXP4> > exp3;
-        return matrix_exp<exp3>(exp3(exp1(a,b),exp2(c,d)));
+        typedef matrix_binary_exp<  exp1  ,  exp2, op_pointwise_multiply> exp3;
+        return matrix_exp<exp3>(exp3(exp1(a.ref(),b.ref()),exp2(c.ref(),d.ref())));
     }
 
 // ----------------------------------------------------------------------------------------
@@ -3072,22 +3097,26 @@ namespace dlib
 
 // ----------------------------------------------------------------------------------------
 
-    template <long lower, long upper, typename EXP>
-    struct op_clamp : has_nondestructive_aliasing, preserves_dimensions<EXP>
+    template <long lower, long upper>
+    struct op_clamp
     {
-        typedef typename EXP::type type;
+        template <typename EXP>
+        struct op : has_nondestructive_aliasing, preserves_dimensions<EXP>
+        {
+            typedef typename EXP::type type;
 
-        template <typename M>
-        static type apply ( const M& m, long r, long c)
-        { 
-            const type temp = m(r,c);
-            if (temp > static_cast<type>(upper))
-                return static_cast<type>(upper);
-            else if (temp < static_cast<type>(lower))
-                return static_cast<type>(lower);
-            else
-                return temp;
-        }
+            template <typename M>
+            static type apply ( const M& m, long r, long c)
+            { 
+                const type temp = m(r,c);
+                if (temp > static_cast<type>(upper))
+                    return static_cast<type>(upper);
+                else if (temp < static_cast<type>(lower))
+                    return static_cast<type>(lower);
+                else
+                    return temp;
+            }
+        };
     };
 
     template <
@@ -3095,11 +3124,11 @@ namespace dlib
         long u,
         typename EXP
         >
-    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_clamp<l,u,EXP> > > clamp (
+    const matrix_exp<matrix_unary_exp<matrix_exp<EXP>,op_clamp<l,u> > > clamp (
         const matrix_exp<EXP>& m
     )
     {
-        typedef matrix_unary_exp<matrix_exp<EXP>,op_clamp<l,u,EXP> > exp;
+        typedef matrix_unary_exp<matrix_exp<EXP>,op_clamp<l,u> > exp;
         return matrix_exp<exp>(exp(m));
     }
 
@@ -3134,29 +3163,32 @@ namespace dlib
 
 // ----------------------------------------------------------------------------------------
 
-    template <typename EXP1, typename EXP2>
-    struct op_scale_columns : has_nondestructive_aliasing
+    struct op_scale_columns
     {
-        typedef typename EXP1::type type;
-        typedef typename EXP1::mem_manager_type mem_manager_type;
-        const static long NR = EXP1::NR;
-        const static long NC = EXP1::NC;
-
-        template <typename M1, typename M2>
-        static type apply ( const M1& m1, const M2& m2 , long r, long c)
-        { return m1(r,c)*m2(c); }
-
-        template <typename M1, typename M2>
-        static long nr (const M1& m1, const M2& ) { return m1.nr(); }
-        template <typename M1, typename M2>
-        static long nc (const M1& m1, const M2& ) { return m1.nc(); }
+        template <typename EXP1, typename EXP2>
+        struct op : has_nondestructive_aliasing
+        {
+            typedef typename EXP1::type type;
+            typedef typename EXP1::mem_manager_type mem_manager_type;
+            const static long NR = EXP1::NR;
+            const static long NC = EXP1::NC;
+
+            template <typename M1, typename M2>
+            static type apply ( const M1& m1, const M2& m2 , long r, long c)
+            { return m1(r,c)*m2(c); }
+
+            template <typename M1, typename M2>
+            static long nr (const M1& m1, const M2& ) { return m1.nr(); }
+            template <typename M1, typename M2>
+            static long nc (const M1& m1, const M2& ) { return m1.nc(); }
+        };
     };
 
     template <
         typename EXP1,
         typename EXP2
         >
-    const matrix_exp<matrix_binary_exp<matrix_exp<EXP1>,matrix_exp<EXP2>,op_scale_columns<EXP1,EXP2> > > scale_columns (
+    const matrix_exp<matrix_binary_exp<matrix_exp<EXP1>,matrix_exp<EXP2>,op_scale_columns> > scale_columns (
         const matrix_exp<EXP1>& m,
         const matrix_exp<EXP2>& v 
     )
@@ -3173,7 +3205,7 @@ namespace dlib
             << "\n\tv.nr(): " << v.nr()
             << "\n\tv.nc(): " << v.nc() 
             );
-        typedef matrix_binary_exp<matrix_exp<EXP1>,matrix_exp<EXP2>,op_scale_columns<EXP1,EXP2> > exp;
+        typedef matrix_binary_exp<matrix_exp<EXP1>,matrix_exp<EXP2>,op_scale_columns> exp;
         return matrix_exp<exp>(exp(m,v));
     }