From dc2d367d062ea093e036172e003ad90d4cb030ee Mon Sep 17 00:00:00 2001
From: Wolfgang Bangerth <bangerth@colostate.edu>
Date: Thu, 14 Sep 2017 14:41:08 -0600
Subject: [PATCH] Allow not specifying the multiplicity in the FESystem
 constructor.

---
 include/deal.II/fe/fe_system.h | 51 ++++++++++++++++++++++++++++++----
 1 file changed, 45 insertions(+), 6 deletions(-)

diff --git a/include/deal.II/fe/fe_system.h b/include/deal.II/fe/fe_system.h
index caa7920589..f9218330df 100644
--- a/include/deal.II/fe/fe_system.h
+++ b/include/deal.II/fe/fe_system.h
@@ -448,12 +448,30 @@ public:
    * elements. The temporary is destroyed again at the end of the code that
    * corresponds to this line, but this does not matter because FESystem
    * creates its own copy of the FE_Q object.
+   *
+   * As a shortcut, this constructor also allows calling
+   * @code
+   *   FESystem<dim> fe (FE_Q<dim>(2)^dim, FE_Q<dim>(1));
+   * @endcode
+   * instead of the more explicit
+   * @code
+   *   FESystem<dim> fe (FE_Q<dim>(2)^dim, FE_Q<dim>(1)^1);
+   * @endcode
+   * In other words, if no multiplicity for an element is explicitly specified
+   * via the exponentiation operation, then it is assumed to be one (as one
+   * would have expected).
    */
   template <class... FEPairs,
-            typename = typename std::enable_if<all_same_as<typename std::decay<FEPairs>::type...,
-                                                           std::pair<std::unique_ptr<FiniteElement<dim, spacedim>>,
-                                                               unsigned int>>::value>::type>
-  FESystem (FEPairs&& ... fe_pairs);
+            typename = typename enable_if_all<
+              (std::is_same<typename std::decay<FEPairs>::type,
+                            std::pair<std::unique_ptr<FiniteElement<dim, spacedim>>, unsigned int>>::value
+               ||
+               std::is_base_of<FiniteElement<dim, spacedim>,
+                               typename std::decay<FEPairs>::type>::value)
+              ...
+              >::type
+            >
+  FESystem (FEPairs &&... fe_pairs);
 
   /**
    * Same as above allowing the following syntax:
@@ -1149,6 +1167,26 @@ namespace
       return fe_system.second > 0;
     });
   }
+
+
+
+  template <int dim, int spacedim>
+  std::pair<std::unique_ptr<FiniteElement<dim, spacedim> >, unsigned int>
+  promote_to_fe_pair (const FiniteElement<dim,spacedim> &fe)
+  {
+    return std::make_pair<std::unique_ptr<FiniteElement<dim, spacedim> >,
+           unsigned int> (std::move(fe.clone()), 1u);
+  }
+
+
+
+  template <int dim, int spacedim>
+  auto
+  promote_to_fe_pair (std::pair<std::unique_ptr<FiniteElement<dim, spacedim> >, unsigned int> &&p)
+  -> decltype(std::forward<std::pair<std::unique_ptr<FiniteElement<dim, spacedim> >, unsigned int> >(p))
+  {
+    return std::forward<std::pair<std::unique_ptr<FiniteElement<dim, spacedim> >, unsigned int> >(p);
+  }
 }
 
 
@@ -1157,10 +1195,11 @@ namespace
 // If we decide to remove the deprecated constructors, we might just use the variadic
 // constructor with a suitable static_assert instead of the std::enable_if.
 template<int dim, int spacedim>
-template <class... FEPairs, typename>
+template <class... FEPairs,
+          typename>
 FESystem<dim,spacedim>::FESystem (FEPairs &&... fe_pairs)
   :
-  FESystem<dim, spacedim> ({std::forward<FEPairs>(fe_pairs)...})
+  FESystem<dim, spacedim> ({promote_to_fe_pair<dim,spacedim>(std::forward<FEPairs>(fe_pairs))...})
 {}
 
 
-- 
2.39.5