diff --git a/include/petsccxxcomplexfix.h b/include/petsccxxcomplexfix.h
index 34cd3db5bfad013c935ddd2a2049899870d2fc75..3ff406c7b2380772a600818da937d8e12fed1cda 100644
--- a/include/petsccxxcomplexfix.h
+++ b/include/petsccxxcomplexfix.h
@@ -41,92 +41,95 @@
      files to prevent these methods from being provided.
 */
 
-#define PETSC_CXX_COMPLEX_FIX(Type) \
-  static inline PetscComplex operator+(const PetscComplex &lhs, const Type &rhs) \
-  { \
-    return const_cast<PetscComplex &>(lhs) + PetscReal(rhs); \
-  } \
-  static inline PetscComplex operator+(const Type &lhs, const PetscComplex &rhs) \
-  { \
-    return PetscReal(lhs) + const_cast<PetscComplex &>(rhs); \
-  } \
-  static inline PetscComplex operator-(const PetscComplex &lhs, const Type &rhs) \
-  { \
-    return const_cast<PetscComplex &>(lhs) - PetscReal(rhs); \
-  } \
-  static inline PetscComplex operator-(const Type &lhs, const PetscComplex &rhs) \
-  { \
-    return PetscReal(lhs) - const_cast<PetscComplex &>(rhs); \
-  } \
-  static inline PetscComplex operator*(const PetscComplex &lhs, const Type &rhs) \
-  { \
-    return const_cast<PetscComplex &>(lhs) * PetscReal(rhs); \
-  } \
-  static inline PetscComplex operator*(const Type &lhs, const PetscComplex &rhs) \
-  { \
-    return PetscReal(lhs) * const_cast<PetscComplex &>(rhs); \
-  } \
-  static inline PetscComplex operator/(const PetscComplex &lhs, const Type &rhs) \
-  { \
-    return const_cast<PetscComplex &>(lhs) / PetscReal(rhs); \
-  } \
-  static inline PetscComplex operator/(const Type &lhs, const PetscComplex &rhs) \
-  { \
-    return PetscReal(lhs) / const_cast<PetscComplex &>(rhs); \
-  } \
-  static inline bool operator==(const PetscComplex &lhs, const Type &rhs) \
-  { \
-    return const_cast<PetscComplex &>(lhs).imag() == PetscReal(0) && const_cast<PetscComplex &>(lhs).real() == PetscReal(rhs); \
-  } \
-  static inline bool operator==(const Type &lhs, const PetscComplex &rhs) \
-  { \
-    return const_cast<PetscComplex &>(rhs).imag() == PetscReal(0) && const_cast<PetscComplex &>(rhs).real() == PetscReal(lhs); \
-  } \
-  static inline bool operator!=(const PetscComplex &lhs, const Type &rhs) \
-  { \
-    return const_cast<PetscComplex &>(lhs).imag() != PetscReal(0) || const_cast<PetscComplex &>(lhs).real() != PetscReal(rhs); \
-  } \
-  static inline bool operator!=(const Type &lhs, const PetscComplex &rhs) \
-  { \
-    return const_cast<PetscComplex &>(rhs).imag() != PetscReal(0) || const_cast<PetscComplex &>(rhs).real() != PetscReal(lhs); \
-  } \
-/* PETSC_CXX_COMPLEX_FIX */
-
 // In PETSc, a quad precision PetscComplex is a C type even with clanguage=cxx, therefore no C++ operator overloading needed for it.
 #if !defined(PETSC_USE_REAL___FLOAT128)
-
-// Provide operator overloading for 'PetscComplex .op. (an integer type or a real type but not PetscReal)'.
-//
-// We enumerate all C/C++ POD (Plain Old Data) types to provide exact overload resolution, to keep the precision change
-// in the Type to PetscReal conversion intact, as intended by users performing these mixed precision operations.
-  #if !defined(PETSC_USE_REAL___FP16) && defined(PETSC_HAVE_REAL___FP16)
-PETSC_CXX_COMPLEX_FIX(__fp16)
+  #include <type_traits>
+// For operations "Atype op Cmplex" or "Cmplex op Atype" with Cmplex being PetscComplex, the built-in support allows Atype to be PetscComplex or PetscReal.
+// We extend Atype to other C++ arithmetic types, and __fp16, __float128 if available.
+// We put Cmplex as a template parameter so that we can enforce Cmplex to be PetscComplex and forbid compilers to convert other types to PetscComplex.
+// This requires C++11 or later.
+template <typename Cmplex, typename Atype> // operation on a complex and an arithmetic type
+struct petsccomplex_extended_type :
+  std::integral_constant<bool, (std::is_same<Cmplex, PetscComplex>::value && std::is_arithmetic<Atype>::value && !std::is_same<Atype, PetscReal>::value)
+  #if defined(PETSC_HAVE_REAL___FP16) && !defined(PETSC_USE_REAL___FP16)
+                                 || std::is_same<Atype, __fp16>::value
   #endif
-
-  #if !defined(PETSC_USE_REAL_SINGLE)
-PETSC_CXX_COMPLEX_FIX(float)
-  #endif
-
-  #if !defined(PETSC_USE_REAL_DOUBLE)
-PETSC_CXX_COMPLEX_FIX(double)
+  #if defined(PETSC_HAVE_REAL___FLOAT128) && !defined(PETSC_USE_REAL___FLOAT128)
+                                 || std::is_same<Atype, __float128>::value
   #endif
-
-PETSC_CXX_COMPLEX_FIX(long double)
-
-  #if defined(PETSC_HAVE_REAL___FLOAT128)
-PETSC_CXX_COMPLEX_FIX(__float128)
-  #endif
-
-PETSC_CXX_COMPLEX_FIX(signed char)
-PETSC_CXX_COMPLEX_FIX(short)
-PETSC_CXX_COMPLEX_FIX(int)
-PETSC_CXX_COMPLEX_FIX(long)
-PETSC_CXX_COMPLEX_FIX(long long)
-
-PETSC_CXX_COMPLEX_FIX(unsigned char)
-PETSC_CXX_COMPLEX_FIX(unsigned short)
-PETSC_CXX_COMPLEX_FIX(unsigned int)
-PETSC_CXX_COMPLEX_FIX(unsigned long)
-PETSC_CXX_COMPLEX_FIX(unsigned long long)
+                         > {
+};
+
+template <typename Cmplex, typename Atype>
+inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, Cmplex>::type operator+(const Atype &lhs, const Cmplex &rhs)
+{
+  return PetscReal(lhs) + rhs;
+}
+
+template <typename Cmplex, typename Atype>
+inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, Cmplex>::type operator+(const Cmplex &lhs, const Atype &rhs)
+{
+  return lhs + PetscReal(rhs);
+}
+
+template <typename Cmplex, typename Atype>
+inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, Cmplex>::type operator-(const Atype &lhs, const Cmplex &rhs)
+{
+  return PetscReal(lhs) - rhs;
+}
+
+template <typename Cmplex, typename Atype>
+inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, Cmplex>::type operator-(const Cmplex &lhs, const Atype &rhs)
+{
+  return lhs - PetscReal(rhs);
+}
+
+template <typename Cmplex, typename Atype>
+inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, Cmplex>::type operator*(const Atype &lhs, const Cmplex &rhs)
+{
+  return PetscReal(lhs) * rhs;
+}
+
+template <typename Cmplex, typename Atype>
+inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, Cmplex>::type operator*(const Cmplex &lhs, const Atype &rhs)
+{
+  return lhs * PetscReal(rhs);
+}
+
+template <typename Cmplex, typename Atype>
+inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, Cmplex>::type operator/(const Atype &lhs, const Cmplex &rhs)
+{
+  return PetscReal(lhs) / rhs;
+}
+
+template <typename Cmplex, typename Atype>
+inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, Cmplex>::type operator/(const Cmplex &lhs, const Atype &rhs)
+{
+  return lhs / PetscReal(rhs);
+}
+
+template <typename Cmplex, typename Atype>
+inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, bool>::type operator==(const Atype &lhs, const Cmplex &rhs)
+{
+  return rhs.imag() == PetscReal(0) && rhs.real() == PetscReal(lhs);
+}
+
+template <typename Cmplex, typename Atype>
+inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, bool>::type operator==(const Cmplex &lhs, const Atype &rhs)
+{
+  return lhs.imag() == PetscReal(0) && lhs.real() == PetscReal(rhs);
+}
+
+template <typename Cmplex, typename Atype>
+inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, bool>::type operator!=(const Atype &lhs, const Cmplex &rhs)
+{
+  return rhs.imag() != PetscReal(0) || rhs.real() != PetscReal(lhs);
+}
+
+template <typename Cmplex, typename Atype>
+inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, bool>::type operator!=(const Cmplex &lhs, const Atype &rhs)
+{
+  return lhs.imag() != PetscReal(0) || lhs.real() != PetscReal(rhs);
+}
 
 #endif
