From 7057437e95670b5512d3db14668d3e78c32eeaa6 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Wed, 11 Feb 2015 08:00:27 -0600 Subject: [PATCH] Introduce a type that can be used to determine whether a template argument is a scalar or not. --- doc/news/changes.h | 4 +- include/deal.II/base/template_constraints.h | 95 ++++++++++++++++++++- 2 files changed, 97 insertions(+), 2 deletions(-) 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.
  1. 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.
    (Wolfgang Bangerth, 2015/02/04)
  2. 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,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 EnableIfScalar@ 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 + * 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 EnableIfScalar::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 + * EnableIfScalar@::type equals @p double, the compiler + * will instantiate a function + * double multiply(const double, const double) from the template + * above. On the other hand, in a context like + * @code + * std::vector v1, v2; + * multiply(v1, v2); + * @endcode + * the compiler will deduce @p T to be std::vector@ but + * because EnableIfScalar@@>::type 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 t1*t2 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 +struct EnableIfScalar; + + +template <> struct EnableIfScalar +{ + typedef double type; +}; + + +template <> struct EnableIfScalar +{ + typedef float type; +}; + + +template <> struct EnableIfScalar +{ + typedef long double type; +}; + + +template <> struct EnableIfScalar +{ + typedef int type; +}; + + +template <> struct EnableIfScalar +{ + typedef unsigned int type; +}; + + + +template struct EnableIfScalar > +{ + typedef std::complex type; +}; + + + + // --------------- inline functions ----------------- @@ -458,7 +552,6 @@ PointerComparison::equal (const T *p1, const T *p2) } - DEAL_II_NAMESPACE_CLOSE #endif -- 2.39.5