From: Wolfgang Bangerth <bangerth@math.tamu.edu>
Date: Wed, 11 Feb 2015 14:00:27 +0000 (-0600)
Subject: Introduce a type that can be used to determine whether a template argument is a scala... 
X-Git-Tag: v8.3.0-rc1~478^2~4
X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7057437e95670b5512d3db14668d3e78c32eeaa6;p=dealii.git

Introduce a type that can be used to determine whether a template argument is a scalar or not.
---

diff --git a/doc/news/changes.h b/doc/news/changes.h
index b193e76b9f..f93ccf2afd 100644
--- a/doc/news/changes.h
+++ b/doc/news/changes.h
@@ -331,7 +331,9 @@ inconvenience this causes.
 
 <ol>
   <li> New: There is now a new class ProductType that can be used
-  to infer the type of the product of two objects.
+  to infer the type of the product of two objects. There is now also
+  a class EnableIfScalar that helps restrict some templates to only
+  cases where a type is a scalar.
   <br>
   (Wolfgang Bangerth, 2015/02/04)
   </li>
diff --git a/include/deal.II/base/template_constraints.h b/include/deal.II/base/template_constraints.h
index acd529d168..a96716b915 100644
--- a/include/deal.II/base/template_constraints.h
+++ b/include/deal.II/base/template_constraints.h
@@ -435,6 +435,100 @@ struct ProductType<std::complex<T>,float>
 
 
 
+/**
+ * This class provides a local typedef @p type that is equal to the
+ * template argument but only if the template argument corresponds to
+ * a scalar type (i.e., one of the floating point types, signed or unsigned
+ * integer, or a complex number). If the template type @p T is not a scalar,
+ * then no class <code>EnableIfScalar@<T@></code> is declared and,
+ * consequently, no local typedef is available.
+ *
+ * The purpose of the class is to disable certain template functions if
+ * one of the arguments is not a scalar number. By way of (nonsensical)
+ * example, consider the following function:
+ * @code
+ *   template <typename T>
+ *   T multiply (const T t1, const T t2) { return t1*t2; }
+ * @endcode
+ * This function can be called with any two arguments of the same type @p T.
+ * This includes arguments for which this clearly makes no sense. Consequently,
+ * one may want to restrict the function to only scalars, and this can be
+ * written as
+ * @code
+ *   template <typename T>
+ *   typename EnableIfScalar<T>::type
+ *   multiply (const T t1, const T t2) { return t1*t2; }
+ * @endcode
+ * At a place where you call the function, the compiler will deduce the
+ * type @p T from the arguments. For example, in
+ * @code
+ *   multiply(1.234, 2.345);
+ * @endcode
+ * it will deduce @p T to be @p double, and because
+ * <code>EnableIfScalar@<double@>::type</code> equals @p double, the compiler
+ * will instantiate a function
+ * <code>double multiply(const double, const double)</code> from the template
+ * above. On the other hand, in a context like
+ * @code
+ *   std::vector<char> v1, v2;
+ *   multiply(v1, v2);
+ * @endcode
+ * the compiler will deduce @p T to be <code>std::vector@<char@></code> but
+ * because <code>EnableIfScalar@<std::vector@<char@>@>::type</code> does not exist
+ * the compiler does not consider the template for instantiation. This technique
+ * is called "Substitution Failure is not an Error (SFINAE)". It makes sure that
+ * the template function can not even be called, rather than leading to a
+ * later error about the fact that the operation <code>t1*t2</code> is not
+ * defined (or may lead to some nonsensical result). It also allows the
+ * declaration of overloads of a function such as @p multiply for different
+ * types of arguments, without resulting in ambiguous call errors by the
+ * compiler.
+ *
+ * @author Wolfgang Bangerth, 2015
+ */
+template <typename T>
+struct EnableIfScalar;
+
+
+template <> struct EnableIfScalar<double> 
+{
+  typedef double type;
+};
+
+
+template <> struct EnableIfScalar<float> 
+{
+  typedef float type;
+};
+
+
+template <> struct EnableIfScalar<long double> 
+{
+  typedef long double type;
+};
+
+
+template <> struct EnableIfScalar<int> 
+{
+  typedef int type;
+};
+
+
+template <> struct EnableIfScalar<unsigned int> 
+{
+  typedef unsigned int type;
+};
+
+
+
+template <typename T> struct EnableIfScalar<std::complex<T> > 
+{
+  typedef std::complex<T> type;
+};
+
+
+
+
 
 // --------------- inline functions -----------------
 
@@ -458,7 +552,6 @@ PointerComparison::equal (const T *p1, const T *p2)
 }
 
 
-
 DEAL_II_NAMESPACE_CLOSE
 
 #endif