diff --git a/include/intx/intx.hpp b/include/intx/intx.hpp
index 4cc95613..bc1fce7a 100644
--- a/include/intx/intx.hpp
+++ b/include/intx/intx.hpp
@@ -374,8 +374,8 @@ inline constexpr uint128 operator~(uint128 x) noexcept
 
 inline constexpr uint128 operator|(uint128 x, uint128 y) noexcept
 {
-    // Clang7: perfect.
-    // GCC8: stupidly uses a vector instruction in all bitwise operators.
+    // Clang: perfect.
+    // GCC 8-12: stupidly uses a vector instruction in all bitwise operators.
     return {x[0] | y[0], x[1] | y[1]};
 }
 
@@ -1120,6 +1120,45 @@ struct uint
     inline constexpr uint& operator/=(const uint& y) noexcept { return *this = *this / y; }
 
     inline constexpr uint& operator%=(const uint& y) noexcept { return *this = *this % y; }
+
+
+    inline constexpr uint operator~() const noexcept
+    {
+        uint z;
+        for (size_t i = 0; i < num_words; ++i)
+            z[i] = ~words_[i];
+        return z;
+    }
+
+    friend inline constexpr uint operator|(const uint& x, const uint& y) noexcept
+    {
+        uint z;
+        for (size_t i = 0; i < num_words; ++i)
+            z[i] = x[i] | y[i];
+        return z;
+    }
+
+    inline constexpr uint& operator|=(const uint& y) noexcept { return *this = *this | y; }
+
+    friend inline constexpr uint operator&(const uint& x, const uint& y) noexcept
+    {
+        uint z;
+        for (size_t i = 0; i < num_words; ++i)
+            z[i] = x[i] & y[i];
+        return z;
+    }
+
+    inline constexpr uint& operator&=(const uint& y) noexcept { return *this = *this & y; }
+
+    friend inline constexpr uint operator^(const uint& x, const uint& y) noexcept
+    {
+        uint z;
+        for (size_t i = 0; i < num_words; ++i)
+            z[i] = x[i] ^ y[i];
+        return z;
+    }
+
+    inline constexpr uint& operator^=(const uint& y) noexcept { return *this = *this ^ y; }
 };
 
 using uint192 = uint<192>;
@@ -1282,42 +1321,6 @@ inline constexpr bool slt(const uint<N>& x, const uint<N>& y) noexcept
     return ((x_neg ^ y_neg) != 0) ? x_neg : x < y;
 }
 
-template <unsigned N>
-inline constexpr uint<N> operator|(const uint<N>& x, const uint<N>& y) noexcept
-{
-    uint<N> z;
-    for (size_t i = 0; i < uint<N>::num_words; ++i)
-        z[i] = x[i] | y[i];
-    return z;
-}
-
-template <unsigned N>
-inline constexpr uint<N> operator&(const uint<N>& x, const uint<N>& y) noexcept
-{
-    uint<N> z;
-    for (size_t i = 0; i < uint<N>::num_words; ++i)
-        z[i] = x[i] & y[i];
-    return z;
-}
-
-template <unsigned N>
-inline constexpr uint<N> operator^(const uint<N>& x, const uint<N>& y) noexcept
-{
-    uint<N> z;
-    for (size_t i = 0; i < uint<N>::num_words; ++i)
-        z[i] = x[i] ^ y[i];
-    return z;
-}
-
-template <unsigned N>
-inline constexpr uint<N> operator~(const uint<N>& x) noexcept
-{
-    uint<N> z;
-    for (size_t i = 0; i < uint<N>::num_words; ++i)
-        z[i] = ~x[i];
-    return z;
-}
-
 
 inline constexpr uint256 operator<<(const uint256& x, uint64_t shift) noexcept
 {
@@ -1842,69 +1845,6 @@ inline constexpr uint<N> bswap(const uint<N>& x) noexcept
 
 // Support for type conversions for binary operators.
 
-template <unsigned N, typename T,
-    typename = typename std::enable_if<std::is_convertible<T, uint<N>>::value>::type>
-inline constexpr uint<N> operator|(const uint<N>& x, const T& y) noexcept
-{
-    return x | uint<N>(y);
-}
-
-template <unsigned N, typename T,
-    typename = typename std::enable_if<std::is_convertible<T, uint<N>>::value>::type>
-inline constexpr uint<N> operator|(const T& x, const uint<N>& y) noexcept
-{
-    return uint<N>(x) | y;
-}
-
-template <unsigned N, typename T,
-    typename = typename std::enable_if<std::is_convertible<T, uint<N>>::value>::type>
-inline constexpr uint<N> operator&(const uint<N>& x, const T& y) noexcept
-{
-    return x & uint<N>(y);
-}
-
-template <unsigned N, typename T,
-    typename = typename std::enable_if<std::is_convertible<T, uint<N>>::value>::type>
-inline constexpr uint<N> operator&(const T& x, const uint<N>& y) noexcept
-{
-    return uint<N>(x) & y;
-}
-
-template <unsigned N, typename T,
-    typename = typename std::enable_if<std::is_convertible<T, uint<N>>::value>::type>
-inline constexpr uint<N> operator^(const uint<N>& x, const T& y) noexcept
-{
-    return x ^ uint<N>(y);
-}
-
-template <unsigned N, typename T,
-    typename = typename std::enable_if<std::is_convertible<T, uint<N>>::value>::type>
-inline constexpr uint<N> operator^(const T& x, const uint<N>& y) noexcept
-{
-    return uint<N>(x) ^ y;
-}
-
-template <unsigned N, typename T,
-    typename = typename std::enable_if<std::is_convertible<T, uint<N>>::value>::type>
-inline constexpr uint<N>& operator|=(uint<N>& x, const T& y) noexcept
-{
-    return x = x | y;
-}
-
-template <unsigned N, typename T,
-    typename = typename std::enable_if<std::is_convertible<T, uint<N>>::value>::type>
-inline constexpr uint<N>& operator&=(uint<N>& x, const T& y) noexcept
-{
-    return x = x & y;
-}
-
-template <unsigned N, typename T,
-    typename = typename std::enable_if<std::is_convertible<T, uint<N>>::value>::type>
-inline constexpr uint<N>& operator^=(uint<N>& x, const T& y) noexcept
-{
-    return x = x ^ y;
-}
-
 template <unsigned N, typename T,
     typename = typename std::enable_if<std::is_convertible<T, uint<N>>::value>::type>
 inline constexpr uint<N>& operator<<=(uint<N>& x, const T& y) noexcept