]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Implement a more generic method of converting between number types. 5251/head
authorJean-Paul Pelteret <jppelteret@gmail.com>
Mon, 16 Oct 2017 07:47:02 +0000 (09:47 +0200)
committerJean-Paul Pelteret <jppelteret@gmail.com>
Mon, 16 Oct 2017 07:47:02 +0000 (09:47 +0200)
This is particularly useful when needing to cast exotic number types to
a floating point numbers, such as might happen when converting between
tensor types.

include/deal.II/base/numbers.h

index 33fcdc6acfa45d261e6ae5cc17b78af9dd400028..c25eadb659261aeec021f64c409c07314a3ca272 100644 (file)
@@ -384,6 +384,36 @@ namespace numbers
 
 namespace internal
 {
+  /**
+   * A test to see if it is possible to convert one number
+   * type to the other.
+   */
+  template<typename From, typename To>
+  struct is_explicitly_convertible
+  {
+    // Source: https://stackoverflow.com/a/16944130
+  private:
+    template<typename T>
+    static void f(T);
+
+    template<typename F, typename T>
+    static constexpr auto test(int) ->
+    decltype(f(static_cast<T>(std::declval<F>())),true)
+    {
+      return true;
+    }
+
+    template<typename F, typename T>
+    static constexpr auto test(...) -> bool
+    {
+      return false;
+    }
+
+  public:
+
+    static bool const value = test<From,To>(0);
+  };
+
   /**
   * The structs below are needed since VectorizedArray<T1> is a POD-type without a constructor and
   * can be a template argument for SymmetricTensor<...,T2> where T2 would equal VectorizedArray<T1>.
@@ -401,6 +431,38 @@ namespace internal
     {
       return t;
     }
+
+    // Below are generic functions that allows an overload for any
+    // type U that is transformable to type T. This is particularly
+    // useful when needing to cast exotic number types
+    // (e.g. auto-differentiable or symbolic numbers) to a floating
+    // point one, such as might  happen when converting between tensor
+    // types.
+
+    // Type T is constructible from F.
+    template<typename F>
+    static T
+    value (const F &f,
+           typename std::enable_if<
+           !std::is_same<typename std::decay<T>::type,typename std::decay<F>::type>::value &&
+           std::is_constructible<T,F>::value
+           >::type * = 0)
+    {
+      return T(f);
+    }
+
+    // Type T is explicitly convertible (but not constructible) from F.
+    template<typename F>
+    static T
+    value (const F &f,
+           typename std::enable_if<
+           !std::is_same<typename std::decay<T>::type,typename std::decay<F>::type>::value &&
+           !std::is_constructible<T,F>::value &&
+           is_explicitly_convertible<const F,T>::value
+           >::type * = 0)
+    {
+      return static_cast<T>(f);
+    }
   };
 
   template <typename T>

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.