1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
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
|