From 85e3ff5d38d22ea236e68edb8389be57805bc900 Mon Sep 17 00:00:00 2001
From: Philip Trettner <Philip.Trettner@rwth-aachen.de>
Date: Mon, 28 Jan 2019 09:07:58 +0100
Subject: [PATCH] fixed operators with scalars

---
 README.md                               |   1 +
 src/tg/detail/macros.hh                 | 210 ++++++++++++------------
 src/tg/detail/operators/ops_pos.hh      |  13 +-
 src/tg/detail/operators/ops_size.hh     |  13 +-
 src/tg/detail/operators/ops_triangle.hh |   6 +
 src/tg/detail/operators/ops_vec.hh      |  13 +-
 6 files changed, 120 insertions(+), 136 deletions(-)

diff --git a/README.md b/README.md
index 5b9e9e5..4f2cf63 100644
--- a/README.md
+++ b/README.md
@@ -79,3 +79,4 @@ None.
 * Benchmark how compile times are affected by includes / templates
 * Add tests that verify optimal assembly generated
 * Fractional and bigint data types
+* Deduction guides
diff --git a/src/tg/detail/macros.hh b/src/tg/detail/macros.hh
index cd9d727..4ac1d13 100644
--- a/src/tg/detail/macros.hh
+++ b/src/tg/detail/macros.hh
@@ -67,105 +67,105 @@
                 ScalarR(a.TG_IMPL_MEMBER(TYPE_A, 3)) OP ScalarR(b.TG_IMPL_MEMBER(TYPE_B, 3))};         \
     }
 
-#define TG_IMPL_DEFINE_BINARY_OP_SCALAR_RIGHT(TYPE, OP)                                                              \
-    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>>                       \
-    constexpr TYPE<1, ScalarR> operator OP(TYPE<1, ScalarA> const& a, ScalarB const& b)                              \
-    {                                                                                                                \
-        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) OP ScalarR(b)};                                                   \
-    }                                                                                                                \
-    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>>                       \
-    constexpr TYPE<2, ScalarR> operator OP(TYPE<2, ScalarA> const& a, ScalarB const& b)                              \
-    {                                                                                                                \
-        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) OP ScalarR(b), ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) OP ScalarR(b)}; \
-    }                                                                                                                \
-    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>>                       \
-    constexpr TYPE<3, ScalarR> operator OP(TYPE<3, ScalarA> const& a, ScalarB const& b)                              \
-    {                                                                                                                \
-        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) OP ScalarR(b), ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) OP ScalarR(b),  \
-                ScalarR(a.TG_IMPL_MEMBER(TYPE, 2)) OP ScalarR(b)};                                                   \
-    }                                                                                                                \
-    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>>                       \
-    constexpr TYPE<4, ScalarR> operator OP(TYPE<4, ScalarA> const& a, ScalarB const& b)                              \
-    {                                                                                                                \
-        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) OP ScalarR(b), ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) OP ScalarR(b),  \
-                ScalarR(a.TG_IMPL_MEMBER(TYPE, 2)) OP ScalarR(b), ScalarR(a.TG_IMPL_MEMBER(TYPE, 3)) OP ScalarR(b)}; \
+#define TG_IMPL_DEFINE_BINARY_OP_SCALAR_RIGHT(TYPE, OP)                                                                               \
+    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<is_scalar<ScalarB>>> \
+    constexpr TYPE<1, ScalarR> operator OP(TYPE<1, ScalarA> const& a, ScalarB const& b)                                               \
+    {                                                                                                                                 \
+        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) OP ScalarR(b)};                                                                    \
+    }                                                                                                                                 \
+    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<is_scalar<ScalarB>>> \
+    constexpr TYPE<2, ScalarR> operator OP(TYPE<2, ScalarA> const& a, ScalarB const& b)                                               \
+    {                                                                                                                                 \
+        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) OP ScalarR(b), ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) OP ScalarR(b)};                  \
+    }                                                                                                                                 \
+    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<is_scalar<ScalarB>>> \
+    constexpr TYPE<3, ScalarR> operator OP(TYPE<3, ScalarA> const& a, ScalarB const& b)                                               \
+    {                                                                                                                                 \
+        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) OP ScalarR(b), ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) OP ScalarR(b),                   \
+                ScalarR(a.TG_IMPL_MEMBER(TYPE, 2)) OP ScalarR(b)};                                                                    \
+    }                                                                                                                                 \
+    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<is_scalar<ScalarB>>> \
+    constexpr TYPE<4, ScalarR> operator OP(TYPE<4, ScalarA> const& a, ScalarB const& b)                                               \
+    {                                                                                                                                 \
+        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) OP ScalarR(b), ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) OP ScalarR(b),                   \
+                ScalarR(a.TG_IMPL_MEMBER(TYPE, 2)) OP ScalarR(b), ScalarR(a.TG_IMPL_MEMBER(TYPE, 3)) OP ScalarR(b)};                  \
     }
 
-#define TG_IMPL_DEFINE_BINARY_OP_SCALAR_LEFT(TYPE, OP)                                                               \
-    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>>                       \
-    constexpr TYPE<1, ScalarR> operator OP(ScalarA const& a, TYPE<1, ScalarB> const& b)                              \
-    {                                                                                                                \
-        return {ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 0))};                                                   \
-    }                                                                                                                \
-    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>>                       \
-    constexpr TYPE<2, ScalarR> operator OP(ScalarA const& a, TYPE<2, ScalarB> const& b)                              \
-    {                                                                                                                \
-        return {ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 0)), ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 1))}; \
-    }                                                                                                                \
-    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>>                       \
-    constexpr TYPE<3, ScalarR> operator OP(ScalarA const& a, TYPE<3, ScalarB> const& b)                              \
-    {                                                                                                                \
-        return {ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 0)), ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 1)),  \
-                ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 2))};                                                   \
-    }                                                                                                                \
-    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>>                       \
-    constexpr TYPE<4, ScalarR> operator OP(ScalarA const& a, TYPE<4, ScalarB> const& b)                              \
-    {                                                                                                                \
-        return {ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 0)), ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 1)),  \
-                ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 2)), ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 3))}; \
+#define TG_IMPL_DEFINE_BINARY_OP_SCALAR_LEFT(TYPE, OP)                                                                                \
+    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<is_scalar<ScalarA>>> \
+    constexpr TYPE<1, ScalarR> operator OP(ScalarA const& a, TYPE<1, ScalarB> const& b)                                               \
+    {                                                                                                                                 \
+        return {ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 0))};                                                                    \
+    }                                                                                                                                 \
+    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<is_scalar<ScalarA>>> \
+    constexpr TYPE<2, ScalarR> operator OP(ScalarA const& a, TYPE<2, ScalarB> const& b)                                               \
+    {                                                                                                                                 \
+        return {ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 0)), ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 1))};                  \
+    }                                                                                                                                 \
+    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<is_scalar<ScalarA>>> \
+    constexpr TYPE<3, ScalarR> operator OP(ScalarA const& a, TYPE<3, ScalarB> const& b)                                               \
+    {                                                                                                                                 \
+        return {ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 0)), ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 1)),                   \
+                ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 2))};                                                                    \
+    }                                                                                                                                 \
+    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<is_scalar<ScalarA>>> \
+    constexpr TYPE<4, ScalarR> operator OP(ScalarA const& a, TYPE<4, ScalarB> const& b)                                               \
+    {                                                                                                                                 \
+        return {ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 0)), ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 1)),                   \
+                ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 2)), ScalarR(a) OP ScalarR(b.TG_IMPL_MEMBER(TYPE, 3))};                  \
     }
 
-#define TG_IMPL_DEFINE_BINARY_OP_SCALAR_DIV(TYPE)                                                                                                                      \
-    /* scalar / type */                                                                                                                                                \
-    TG_IMPL_DEFINE_BINARY_OP_SCALAR_LEFT(TYPE, /)                                                                                                                      \
-    /* type / scalar, optimized if result is floating point */                                                                                                         \
-    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<is_floating_point<ScalarR>>>                          \
-    constexpr TYPE<1, ScalarR> operator/(TYPE<1, ScalarA> const& a, ScalarB const& b)                                                                                  \
-    {                                                                                                                                                                  \
-        auto inv_b = ScalarR(1) / ScalarR(b);                                                                                                                          \
-        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) * inv_b};                                                                                                           \
-    }                                                                                                                                                                  \
-    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<is_floating_point<ScalarR>>>                          \
-    constexpr TYPE<2, ScalarR> operator/(TYPE<2, ScalarA> const& a, ScalarB const& b)                                                                                  \
-    {                                                                                                                                                                  \
-        auto inv_b = ScalarR(1) / ScalarR(b);                                                                                                                          \
-        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) * inv_b, ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) * inv_b};                                                               \
-    }                                                                                                                                                                  \
-    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<is_floating_point<ScalarR>>>                          \
-    constexpr TYPE<3, ScalarR> operator/(TYPE<3, ScalarA> const& a, ScalarB const& b)                                                                                  \
-    {                                                                                                                                                                  \
-        auto inv_b = ScalarR(1) / ScalarR(b);                                                                                                                          \
-        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) * inv_b, ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) * inv_b, ScalarR(a.TG_IMPL_MEMBER(TYPE, 2)) * inv_b};                   \
-    }                                                                                                                                                                  \
-    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<is_floating_point<ScalarR>>>                          \
-    constexpr TYPE<4, ScalarR> operator/(TYPE<4, ScalarA> const& a, ScalarB const& b)                                                                                  \
-    {                                                                                                                                                                  \
-        auto inv_b = ScalarR(1) / ScalarR(b);                                                                                                                          \
-        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) * inv_b, ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) * inv_b, ScalarR(a.TG_IMPL_MEMBER(TYPE, 2)) * inv_b,                    \
-                ScalarR(a.TG_IMPL_MEMBER(TYPE, 3)) * inv_b};                                                                                                           \
-    }                                                                                                                                                                  \
-    /* type / scalar, for non-float result */                                                                                                                          \
-    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<!is_floating_point<ScalarR>>, class = detail::unused> \
-    constexpr TYPE<1, ScalarR> operator/(TYPE<1, ScalarA> const& a, ScalarB const& b)                                                                                  \
-    {                                                                                                                                                                  \
-        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) / ScalarR(b)};                                                                                                      \
-    }                                                                                                                                                                  \
-    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<!is_floating_point<ScalarR>>, class = detail::unused> \
-    constexpr TYPE<2, ScalarR> operator/(TYPE<2, ScalarA> const& a, ScalarB const& b)                                                                                  \
-    {                                                                                                                                                                  \
-        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) / ScalarR(b), ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) / ScalarR(b)};                                                     \
-    }                                                                                                                                                                  \
-    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<!is_floating_point<ScalarR>>, class = detail::unused> \
-    constexpr TYPE<3, ScalarR> operator/(TYPE<3, ScalarA> const& a, ScalarB const& b)                                                                                  \
-    {                                                                                                                                                                  \
-        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) / ScalarR(b), ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) / ScalarR(b),                                                      \
-                ScalarR(a.TG_IMPL_MEMBER(TYPE, 2)) / ScalarR(b)};                                                                                                      \
-    }                                                                                                                                                                  \
-    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<!is_floating_point<ScalarR>>, class = detail::unused> \
-    constexpr TYPE<4, ScalarR> operator/(TYPE<4, ScalarA> const& a, ScalarB const& b)                                                                                  \
-    {                                                                                                                                                                  \
-        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) / ScalarR(b), ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) / ScalarR(b),                                                      \
-                ScalarR(a.TG_IMPL_MEMBER(TYPE, 2)) / ScalarR(b), ScalarR(a.TG_IMPL_MEMBER(TYPE, 3)) / ScalarR(b)};                                                     \
+#define TG_IMPL_DEFINE_BINARY_OP_SCALAR_DIV(TYPE)                                                                                                                                            \
+    /* scalar / type */                                                                                                                                                                      \
+    TG_IMPL_DEFINE_BINARY_OP_SCALAR_LEFT(TYPE, /)                                                                                                                                            \
+    /* type / scalar, optimized if result is floating point */                                                                                                                               \
+    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<is_floating_point<ScalarR> && is_scalar<ScalarB>>>                          \
+    constexpr TYPE<1, ScalarR> operator/(TYPE<1, ScalarA> const& a, ScalarB const& b)                                                                                                        \
+    {                                                                                                                                                                                        \
+        auto inv_b = ScalarR(1) / ScalarR(b);                                                                                                                                                \
+        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) * inv_b};                                                                                                                                 \
+    }                                                                                                                                                                                        \
+    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<is_floating_point<ScalarR> && is_scalar<ScalarB>>>                          \
+    constexpr TYPE<2, ScalarR> operator/(TYPE<2, ScalarA> const& a, ScalarB const& b)                                                                                                        \
+    {                                                                                                                                                                                        \
+        auto inv_b = ScalarR(1) / ScalarR(b);                                                                                                                                                \
+        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) * inv_b, ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) * inv_b};                                                                                     \
+    }                                                                                                                                                                                        \
+    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<is_floating_point<ScalarR> && is_scalar<ScalarB>>>                          \
+    constexpr TYPE<3, ScalarR> operator/(TYPE<3, ScalarA> const& a, ScalarB const& b)                                                                                                        \
+    {                                                                                                                                                                                        \
+        auto inv_b = ScalarR(1) / ScalarR(b);                                                                                                                                                \
+        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) * inv_b, ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) * inv_b, ScalarR(a.TG_IMPL_MEMBER(TYPE, 2)) * inv_b};                                         \
+    }                                                                                                                                                                                        \
+    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<is_floating_point<ScalarR> && is_scalar<ScalarB>>>                          \
+    constexpr TYPE<4, ScalarR> operator/(TYPE<4, ScalarA> const& a, ScalarB const& b)                                                                                                        \
+    {                                                                                                                                                                                        \
+        auto inv_b = ScalarR(1) / ScalarR(b);                                                                                                                                                \
+        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) * inv_b, ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) * inv_b, ScalarR(a.TG_IMPL_MEMBER(TYPE, 2)) * inv_b,                                          \
+                ScalarR(a.TG_IMPL_MEMBER(TYPE, 3)) * inv_b};                                                                                                                                 \
+    }                                                                                                                                                                                        \
+    /* type / scalar, for non-float result */                                                                                                                                                \
+    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<!is_floating_point<ScalarR> && is_scalar<ScalarB>>, class = detail::unused> \
+    constexpr TYPE<1, ScalarR> operator/(TYPE<1, ScalarA> const& a, ScalarB const& b)                                                                                                        \
+    {                                                                                                                                                                                        \
+        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) / ScalarR(b)};                                                                                                                            \
+    }                                                                                                                                                                                        \
+    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<!is_floating_point<ScalarR> && is_scalar<ScalarB>>, class = detail::unused> \
+    constexpr TYPE<2, ScalarR> operator/(TYPE<2, ScalarA> const& a, ScalarB const& b)                                                                                                        \
+    {                                                                                                                                                                                        \
+        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) / ScalarR(b), ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) / ScalarR(b)};                                                                           \
+    }                                                                                                                                                                                        \
+    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<!is_floating_point<ScalarR> && is_scalar<ScalarB>>, class = detail::unused> \
+    constexpr TYPE<3, ScalarR> operator/(TYPE<3, ScalarA> const& a, ScalarB const& b)                                                                                                        \
+    {                                                                                                                                                                                        \
+        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) / ScalarR(b), ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) / ScalarR(b),                                                                            \
+                ScalarR(a.TG_IMPL_MEMBER(TYPE, 2)) / ScalarR(b)};                                                                                                                            \
+    }                                                                                                                                                                                        \
+    template <class ScalarA, class ScalarB, class ScalarR = promoted_scalar<ScalarA, ScalarB>, class = enable_if<!is_floating_point<ScalarR> && is_scalar<ScalarB>>, class = detail::unused> \
+    constexpr TYPE<4, ScalarR> operator/(TYPE<4, ScalarA> const& a, ScalarB const& b)                                                                                                        \
+    {                                                                                                                                                                                        \
+        return {ScalarR(a.TG_IMPL_MEMBER(TYPE, 0)) / ScalarR(b), ScalarR(a.TG_IMPL_MEMBER(TYPE, 1)) / ScalarR(b),                                                                            \
+                ScalarR(a.TG_IMPL_MEMBER(TYPE, 2)) / ScalarR(b), ScalarR(a.TG_IMPL_MEMBER(TYPE, 3)) / ScalarR(b)};                                                                           \
     }
 
 #define TG_IMPL_DEFINE_BINARY_OP_SCALAR(TYPE, OP) TG_IMPL_DEFINE_BINARY_OP_SCALAR_LEFT(TYPE, OP) TG_IMPL_DEFINE_BINARY_OP_SCALAR_RIGHT(TYPE, OP)
@@ -216,18 +216,10 @@
             (a.TG_IMPL_MEMBER(TYPE_A, 2) OP b.TG_IMPL_MEMBER(TYPE_B, 2))REDUCE(a.TG_IMPL_MEMBER(TYPE_A, 3) OP b.TG_IMPL_MEMBER(TYPE_B, 3)));           \
     }
 
-#define TG_IMPL_DEFINE_ASSIGNMENT_OP(TYPE_THIS, TYPE_THAT, OP)                                                                                    \
-    template <int D, class ScalarA, class ScalarB>                                                                                                \
-    constexpr auto operator OP##=(TYPE_THIS<D, ScalarA>& lhs, TYPE_THAT<D, ScalarB> const& rhs)->decltype(TYPE_THIS<D, ScalarA>(lhs OP rhs), lhs) \
-    {                                                                                                                                             \
-        lhs = TYPE_THIS<D, ScalarA>(lhs OP rhs);                                                                                                  \
-        return lhs;                                                                                                                               \
-    }
-
-#define TG_IMPL_DEFINE_ASSIGNMENT_OP_SCALAR(TYPE_THIS, OP)                                                                          \
-    template <int D, class ScalarA, class ScalarB>                                                                                  \
-    constexpr auto operator OP##=(TYPE_THIS<D, ScalarA>& lhs, ScalarB const& rhs)->decltype(TYPE_THIS<D, ScalarA>(lhs OP rhs), lhs) \
-    {                                                                                                                               \
-        lhs = TYPE_THIS<D, ScalarA>(lhs OP rhs);                                                                                    \
-        return lhs;                                                                                                                 \
+#define TG_IMPL_DEFINE_ASSIGNMENT_OP(TYPE_THIS, OP)                                                                           \
+    template <int D, class ScalarA, class T>                                                                                  \
+    constexpr auto operator OP##=(TYPE_THIS<D, ScalarA>& lhs, T const& rhs)->decltype(TYPE_THIS<D, ScalarA>(lhs OP rhs), lhs) \
+    {                                                                                                                         \
+        lhs = TYPE_THIS<D, ScalarA>(lhs OP rhs);                                                                              \
+        return lhs;                                                                                                           \
     }
diff --git a/src/tg/detail/operators/ops_pos.hh b/src/tg/detail/operators/ops_pos.hh
index d11b019..aa7c289 100644
--- a/src/tg/detail/operators/ops_pos.hh
+++ b/src/tg/detail/operators/ops_pos.hh
@@ -30,14 +30,9 @@ TG_IMPL_DEFINE_BINARY_OP_SCALAR(pos, *);
 TG_IMPL_DEFINE_BINARY_OP_SCALAR_DIV(pos);
 
 // assignment ops
-TG_IMPL_DEFINE_ASSIGNMENT_OP(pos, vec, +);
-TG_IMPL_DEFINE_ASSIGNMENT_OP(pos, vec, -);
-TG_IMPL_DEFINE_ASSIGNMENT_OP(pos, size, *);
-TG_IMPL_DEFINE_ASSIGNMENT_OP(pos, size, /);
-
-TG_IMPL_DEFINE_ASSIGNMENT_OP_SCALAR(pos, +);
-TG_IMPL_DEFINE_ASSIGNMENT_OP_SCALAR(pos, -);
-TG_IMPL_DEFINE_ASSIGNMENT_OP_SCALAR(pos, *);
-TG_IMPL_DEFINE_ASSIGNMENT_OP_SCALAR(pos, /);
+TG_IMPL_DEFINE_ASSIGNMENT_OP(pos, +);
+TG_IMPL_DEFINE_ASSIGNMENT_OP(pos, -);
+TG_IMPL_DEFINE_ASSIGNMENT_OP(pos, *);
+TG_IMPL_DEFINE_ASSIGNMENT_OP(pos, /);
 
 } // namespace tg
diff --git a/src/tg/detail/operators/ops_size.hh b/src/tg/detail/operators/ops_size.hh
index 5b71a65..ce64a22 100644
--- a/src/tg/detail/operators/ops_size.hh
+++ b/src/tg/detail/operators/ops_size.hh
@@ -25,13 +25,8 @@ TG_IMPL_DEFINE_BINARY_OP_SCALAR(size, *);
 TG_IMPL_DEFINE_BINARY_OP_SCALAR_DIV(size);
 
 // assignment ops
-TG_IMPL_DEFINE_ASSIGNMENT_OP(size, size, +);
-TG_IMPL_DEFINE_ASSIGNMENT_OP(size, size, -);
-TG_IMPL_DEFINE_ASSIGNMENT_OP(size, size, *);
-TG_IMPL_DEFINE_ASSIGNMENT_OP(size, size, /);
-
-TG_IMPL_DEFINE_ASSIGNMENT_OP_SCALAR(size, +);
-TG_IMPL_DEFINE_ASSIGNMENT_OP_SCALAR(size, -);
-TG_IMPL_DEFINE_ASSIGNMENT_OP_SCALAR(size, *);
-TG_IMPL_DEFINE_ASSIGNMENT_OP_SCALAR(size, /);
+TG_IMPL_DEFINE_ASSIGNMENT_OP(size, +);
+TG_IMPL_DEFINE_ASSIGNMENT_OP(size, -);
+TG_IMPL_DEFINE_ASSIGNMENT_OP(size, *);
+TG_IMPL_DEFINE_ASSIGNMENT_OP(size, /);
 } // namespace tg
diff --git a/src/tg/detail/operators/ops_triangle.hh b/src/tg/detail/operators/ops_triangle.hh
index 2b5b278..3662988 100644
--- a/src/tg/detail/operators/ops_triangle.hh
+++ b/src/tg/detail/operators/ops_triangle.hh
@@ -91,4 +91,10 @@ constexpr triangle<D, ScalarT> operator/(triangle<D, ScalarT> const& a, size<D,
     return r;
 }
 
+// assignment ops
+TG_IMPL_DEFINE_ASSIGNMENT_OP(triangle, +);
+TG_IMPL_DEFINE_ASSIGNMENT_OP(triangle, -);
+TG_IMPL_DEFINE_ASSIGNMENT_OP(triangle, *);
+TG_IMPL_DEFINE_ASSIGNMENT_OP(triangle, /);
+
 } // namespace tg
diff --git a/src/tg/detail/operators/ops_vec.hh b/src/tg/detail/operators/ops_vec.hh
index 964c3dd..6f3574a 100644
--- a/src/tg/detail/operators/ops_vec.hh
+++ b/src/tg/detail/operators/ops_vec.hh
@@ -25,13 +25,8 @@ TG_IMPL_DEFINE_BINARY_OP_SCALAR(vec, *);
 TG_IMPL_DEFINE_BINARY_OP_SCALAR_DIV(vec);
 
 // assignment ops
-TG_IMPL_DEFINE_ASSIGNMENT_OP(vec, vec, +);
-TG_IMPL_DEFINE_ASSIGNMENT_OP(vec, vec, -);
-TG_IMPL_DEFINE_ASSIGNMENT_OP(vec, size, *);
-TG_IMPL_DEFINE_ASSIGNMENT_OP(vec, size, /);
-
-TG_IMPL_DEFINE_ASSIGNMENT_OP_SCALAR(vec, +);
-TG_IMPL_DEFINE_ASSIGNMENT_OP_SCALAR(vec, -);
-TG_IMPL_DEFINE_ASSIGNMENT_OP_SCALAR(vec, *);
-TG_IMPL_DEFINE_ASSIGNMENT_OP_SCALAR(vec, /);
+TG_IMPL_DEFINE_ASSIGNMENT_OP(vec, +);
+TG_IMPL_DEFINE_ASSIGNMENT_OP(vec, -);
+TG_IMPL_DEFINE_ASSIGNMENT_OP(vec, *);
+TG_IMPL_DEFINE_ASSIGNMENT_OP(vec, /);
 } // namespace tg
-- 
GitLab