From 8bf3862f54826a6efe382ed853a2a2b364046745 Mon Sep 17 00:00:00 2001
From: Simon Praetorius <simon.praetorius@tu-dresden.de>
Date: Sun, 13 Jan 2019 15:31:24 +0100
Subject: [PATCH] introduce macros FWD and TYPEOF to reducine typing of
 std::forward and decltype

---
 src/amdis/Assembler.hpp                       |   2 +-
 src/amdis/DataTransfer.inc.hpp                |   3 +-
 src/amdis/DirichletBC.hpp                     |   8 +-
 src/amdis/GridFunctionOperator.hpp            |  18 ++-
 src/amdis/Integrate.hpp                       |  22 ++-
 src/amdis/Marker.hpp                          |  15 +-
 src/amdis/OperatorList.hpp                    |   6 +-
 src/amdis/Output.hpp                          |  26 ++--
 src/amdis/PeriodicBC.hpp                      |   2 +-
 src/amdis/PeriodicBC.inc.hpp                  |   2 +-
 src/amdis/common/ClonablePtr.hpp              | 127 +++++++++++++++++
 src/amdis/common/Concepts.hpp                 |   2 +-
 src/amdis/common/ConcurrentCache.hpp          |  11 +-
 src/amdis/common/FieldTraits.hpp              |  16 +++
 src/amdis/common/MultiTypeMatrix.hpp          |   2 +-
 src/amdis/common/MultiTypeVector.hpp          |   2 +-
 src/amdis/common/ScalarTypes.hpp              |  41 ++++++
 src/amdis/common/StaticSize.hpp               |  12 +-
 src/amdis/common/Transposed.hpp               |   6 +-
 src/amdis/common/TypeTraits.hpp               |  10 ++
 src/amdis/common/Utility.hpp                  | 130 ++++++++++++++++++
 src/amdis/common/ValueCategory.hpp            |   2 +-
 .../gridfunctions/AnalyticGridFunction.hpp    |   2 +-
 src/amdis/gridfunctions/DOFVectorView.hpp     |   7 +-
 .../gridfunctions/DerivativeGridFunction.hpp  |   2 +-
 .../gridfunctions/DiscreteFunction.inc.hpp    |   6 +-
 .../gridfunctions/FunctorGridFunction.hpp     |  12 +-
 .../gridfunctions/GridFunctionConcepts.hpp    |   4 +-
 .../gridfunctions/OperationsGridFunction.hpp  |  56 ++++----
 src/amdis/operations/Basic.hpp                |   2 +-
 src/amdis/operations/Composer.hpp             |  11 +-
 src/amdis/typetree/RangeType.hpp              |   2 +-
 src/amdis/typetree/Traversal.hpp              |  17 +--
 33 files changed, 451 insertions(+), 135 deletions(-)
 create mode 100644 src/amdis/common/ClonablePtr.hpp
 create mode 100644 src/amdis/common/FieldTraits.hpp
 create mode 100644 src/amdis/common/ScalarTypes.hpp
 create mode 100644 src/amdis/common/Utility.hpp

diff --git a/src/amdis/Assembler.hpp b/src/amdis/Assembler.hpp
index cd1aaa75..6c1c8362 100644
--- a/src/amdis/Assembler.hpp
+++ b/src/amdis/Assembler.hpp
@@ -138,7 +138,7 @@ namespace AMDiS
   template <class LocalContext, class Operator, class... Nodes>
   auto makeAssembler(Operator&& op, Nodes const&...)
   {
-    return Assembler<LocalContext, Underlying_t<Operator>, Nodes...>{std::forward<Operator>(op)};
+    return Assembler<LocalContext, Underlying_t<Operator>, Nodes...>{FWD(op)};
   }
 
 } // end namespace AMDiS
diff --git a/src/amdis/DataTransfer.inc.hpp b/src/amdis/DataTransfer.inc.hpp
index 799009cd..8d33b5e4 100644
--- a/src/amdis/DataTransfer.inc.hpp
+++ b/src/amdis/DataTransfer.inc.hpp
@@ -82,8 +82,7 @@ namespace AMDiS
       }
     };
 
-    using NodeDataTransferContainer = std::decay_t<decltype(
-      makeTreeContainer<Tree, NDT>(std::declval<const Tree&>(), NDT()))>;
+    using NodeDataTransferContainer = TYPEOF(makeTreeContainer<Tree, NDT>(std::declval<const Tree&>(), NDT()));
 
     // Returns the Node's NodeElementData
     struct NodeElementData
diff --git a/src/amdis/DirichletBC.hpp b/src/amdis/DirichletBC.hpp
index 344d1076..10e932b9 100644
--- a/src/amdis/DirichletBC.hpp
+++ b/src/amdis/DirichletBC.hpp
@@ -41,16 +41,16 @@ namespace AMDiS
     template <class BM, class Values,
       REQUIRES(Concepts::Functor<Values, Range(Domain)>) >
     DirichletBC(BM&& boundaryManager, BoundaryType id, Values&& values)
-      : Super(std::forward<BM>(boundaryManager), id)
-      , values_(std::forward<Values>(values))
+      : Super(FWD(boundaryManager), id)
+      , values_(FWD(values))
     {}
 
     template <class Predicate, class Values,
       REQUIRES(Concepts::Functor<Predicate, bool(Domain)>),
       REQUIRES(Concepts::Functor<Values, Range(Domain)>)>
     DirichletBC(Predicate&& predicate, Values&& values)
-      : predicate_(std::forward<Predicate>(predicate))
-      , values_(std::forward<Values>(values))
+      : predicate_(FWD(predicate))
+      , values_(FWD(values))
     {}
 
     template <class Intersection>
diff --git a/src/amdis/GridFunctionOperator.hpp b/src/amdis/GridFunctionOperator.hpp
index b3339453..18d93071 100644
--- a/src/amdis/GridFunctionOperator.hpp
+++ b/src/amdis/GridFunctionOperator.hpp
@@ -70,7 +70,7 @@ namespace AMDiS
      **/
     template <class GF>
     GridFunctionOperatorBase(GF&& gridFct, int termOrder)
-      : gridFct_(std::forward<GF>(gridFct))
+      : gridFct_(FWD(gridFct))
       , termOrder_(termOrder)
     {}
 
@@ -80,7 +80,7 @@ namespace AMDiS
     {
       using ctype = typename Geometry::ctype;
       quadFactory_.emplace(
-        makeQuadratureFactory<ctype, LocalContext::mydimension, LocalFunction>(std::forward<PreQuadFactory>(pre)));
+        makeQuadratureFactory<ctype, LocalContext::mydimension, LocalFunction>(FWD(pre)));
     }
 
   protected:
@@ -157,14 +157,14 @@ namespace AMDiS
     template <class... Args,
       std::enable_if_t<Dune::Std::is_detected<Constructable, Transposed, Args...>::value, int> = 0>
     GridFunctionOperatorTransposed(Args&&... args)
-      : transposedOp_(std::forward<Args>(args)...)
+      : transposedOp_(FWD(args)...)
     {}
 
     /// Redirects the setQuadFactory call top the transposed operator
     template <class PreQuadFactory>
     void setQuadFactory(PreQuadFactory&& pre)
     {
-      transposedOp_.setQuadFactory(std::forward<PreQuadFactory>(pre));
+      transposedOp_.setQuadFactory(FWD(pre));
     }
 
   private:
@@ -210,9 +210,8 @@ namespace AMDiS
   template <class Tag, class Expr, class... QuadratureArgs>
   auto makeOperator(Tag tag, Expr&& expr, QuadratureArgs&&... args)
   {
-    auto pqf = makePreQuadratureFactory(std::forward<QuadratureArgs>(args)...);
-    using PreGridFctOp = PreGridFunctionOperator<Tag, std::decay_t<Expr>, decltype(pqf)>;
-    return PreGridFctOp{tag, std::forward<Expr>(expr), std::move(pqf)};
+    auto pqf = makePreQuadratureFactory(FWD(args)...);
+    return PreGridFunctionOperator<Tag, TYPEOF(expr), TYPEOF(pqf)>{tag, FWD(expr), std::move(pqf)};
   }
 
   /** @} **/
@@ -238,9 +237,8 @@ namespace AMDiS
   template <class Context, class Tag, class GF, class QF>
   auto makeGridFunctionOperator(Tag tag, GF&& gf, QF&& qf)
   {
-    using GridFctOp = GridFunctionOperator<Tag, Context, std::decay_t<GF>>;
-    GridFctOp gfo{tag, std::forward<GF>(gf)};
-    gfo.setQuadFactory(std::forward<QF>(qf));
+    GridFunctionOperator<Tag, Context, TYPEOF(gf)> gfo{tag, FWD(gf)};
+    gfo.setQuadFactory(FWD(qf));
     return gfo;
   }
 
diff --git a/src/amdis/Integrate.hpp b/src/amdis/Integrate.hpp
index 08d527a1..2a952268 100644
--- a/src/amdis/Integrate.hpp
+++ b/src/amdis/Integrate.hpp
@@ -11,9 +11,9 @@ namespace AMDiS
     template <class GF, class GridView, class QuadProvider>
     auto integrateImpl(GF&& gf, GridView const& gridView, QuadProvider makeQuad)
     {
-      auto localFct = localFunction(std::forward<GF>(gf));
+      auto localFct = localFunction(FWD(gf));
 
-      using GridFct = std::decay_t<GF>;
+      using GridFct = remove_cvref_t<GF>;
       using Range = typename GridFct::Range;
       Range result(0);
 
@@ -34,7 +34,7 @@ namespace AMDiS
     template <class GF, class GridView, class QuadProvider>
     auto integrateImpl(GF&& gf, GridView const& gv, QuadProvider makeQuad, std::true_type)
     {
-      return integrateImpl(std::forward<GF>(gf), gv, makeQuad);
+      return integrateImpl(FWD(gf), gv, makeQuad);
     }
 
     template <class GF, class GV, class QP>
@@ -55,10 +55,10 @@ namespace AMDiS
   template <class Expr, class GridView>
   auto integrate(Expr&& expr, GridView const& gridView)
   {
-    auto&& gridFct = makeGridFunction(std::forward<Expr>(expr), gridView);
+    auto&& gridFct = makeGridFunction(FWD(expr), gridView);
 
     // test whether the gridFct model `Concepts::HasLocalFunctionOrder`
-    using GF = std::decay_t<decltype(gridFct)>;
+    using GF = TYPEOF(gridFct);
     static const bool expr_has_order = Concepts::HasLocalFunctionOrder<GF>;
     static_assert(expr_has_order,
       "Polynomial degree of expression can not be deduced. You need to provide an explicit value for the quadrature degree or a quadrature rule in `integrate()`.");
@@ -66,8 +66,7 @@ namespace AMDiS
     using Rules = Dune::QuadratureRules<typename GridView::ctype, GridView::dimension>;
     auto makeQuad = [](auto&& t, auto&& lf) { return Rules::rule(t, order(lf)); };
 
-    return Impl::integrateImpl(std::forward<decltype(gridFct)>(gridFct), gridView, makeQuad,
-      std::integral_constant<bool,expr_has_order>{});
+    return Impl::integrateImpl(FWD(gridFct), gridView, makeQuad, bool_<expr_has_order>);
   }
 
 
@@ -83,9 +82,8 @@ namespace AMDiS
     class QuadratureRule = Dune::QuadratureRule<typename GridView::ctype, GridView::dimension>>
   auto integrate(Expr&& expr, GridView const& gridView, QuadratureRule const& quad)
   {
-    auto&& gridFct = makeGridFunction(std::forward<Expr>(expr), gridView);
-    return Impl::integrateImpl(std::forward<decltype(gridFct)>(gridFct), gridView,
-      [&](auto&&, auto&&) { return quad; });
+    auto&& gridFct = makeGridFunction(FWD(expr), gridView);
+    return Impl::integrateImpl(FWD(gridFct), gridView, [&](auto&&, auto&&) { return quad; });
   }
 
 
@@ -102,8 +100,8 @@ namespace AMDiS
   {
     using Rules = Dune::QuadratureRules<typename GridView::ctype, GridView::dimension>;
 
-    auto&& gridFct = makeGridFunction(std::forward<Expr>(expr), gridView);
-    return Impl::integrateImpl(std::forward<decltype(gridFct)>(gridFct), gridView,
+    auto&& gridFct = makeGridFunction(FWD(expr), gridView);
+    return Impl::integrateImpl(FWD(gridFct), gridView,
       [&](auto const& type, auto&&) { return Rules::rule(type, degree, qt); });
   }
 
diff --git a/src/amdis/Marker.hpp b/src/amdis/Marker.hpp
index 83c62e52..48f5ccd2 100644
--- a/src/amdis/Marker.hpp
+++ b/src/amdis/Marker.hpp
@@ -8,6 +8,7 @@
 #include <dune/grid/common/grid.hh>
 
 #include <amdis/common/ConceptsBase.hpp>
+#include <amdis/common/TypeTraits.hpp>
 
 #include <amdis/gridfunctions/GridFunctionConcepts.hpp>
 
@@ -382,7 +383,7 @@ namespace AMDiS
     template <class GF>
     GridFunctionMarker(std::string const& name, std::shared_ptr<Grid> const& grid, GF&& gf)
       : Super{name, grid}
-      , gridFct_{makeGridFunction(std::forward<GF>(gf), grid->leafGridView())}
+      , gridFct_{makeGridFunction(FWD(gf), grid->leafGridView())}
     {}
 
     /// \brief Implementation of \ref Marker::markElement. Does nothing since marking is
@@ -402,11 +403,10 @@ namespace AMDiS
 
 #if DUNE_HAVE_CXX_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
   // Deduction guide for GridFunctionMarker class
-  template <class Grid, class PreGridFct>
-  GridFunctionMarker(std::string const& name, std::shared_ptr<Grid> const& grid,
-                     PreGridFct&& preGridFct)
+  template <class Grid, class GF>
+  GridFunctionMarker(std::string const& name, std::shared_ptr<Grid> const& grid, GF&& gf)
     -> GridFunctionMarker<Grid,
-          std::decay_t<decltype(makeGridFunction(std::forward<PreGridFct>(preGridFct), grid->leafGridView()))>>;
+          TYPEOF( makeGridFunction(FWD(gf), grid->leafGridView()) )>;
 #endif
 
   // Generator function for GridFunctionMarker class
@@ -414,9 +414,8 @@ namespace AMDiS
   auto makeGridFunctionMarker(std::string const& name, std::shared_ptr<Grid> const& grid,
                               PreGridFct&& preGridFct)
   {
-    auto gridFct = makeGridFunction(std::forward<PreGridFct>(preGridFct), grid->leafGridView());
-    using GridFct = decltype(gridFct);
-    return GridFunctionMarker<Grid,GridFct>{name, grid, gridFct};
+    auto gridFct = makeGridFunction(FWD(preGridFct), grid->leafGridView());
+    return GridFunctionMarker<Grid,TYPEOF(gridFct)>{name, grid, std::move(gridFct)};
   }
 
 } // end namespace AMDiS
diff --git a/src/amdis/OperatorList.hpp b/src/amdis/OperatorList.hpp
index b0807c85..35adb2c9 100644
--- a/src/amdis/OperatorList.hpp
+++ b/src/amdis/OperatorList.hpp
@@ -76,19 +76,19 @@ namespace AMDiS
       template <class Op>
       void push(tag::element_operator<Element>, Op&& op)
       {
-        element_.emplace_back(std::forward<Op>(op));
+        element_.emplace_back(FWD(op));
       }
 
       template <class Op>
       void push(tag::intersection_operator<Intersection>, Op&& op)
       {
-        intersection_.emplace_back(std::forward<Op>(op));
+        intersection_.emplace_back(FWD(op));
       }
 
       template <class Op>
       void push(tag::boundary_operator<Intersection> b, Op&& op)
       {
-        boundary_.push_back({std::forward<Op>(op), b});
+        boundary_.push_back({FWD(op), b});
       }
 
 
diff --git a/src/amdis/Output.hpp b/src/amdis/Output.hpp
index af4d5ff3..91264e57 100644
--- a/src/amdis/Output.hpp
+++ b/src/amdis/Output.hpp
@@ -22,6 +22,8 @@
 #include <fmt/core.h>
 #include <fmt/ostream.h>
 
+#include <amdis/common/TypeTraits.hpp>
+
 /**
  * \def AMDIS_ENABLE_MSG_DBG
  * \brief The preprocessor constant enables the functions \ref AMDiS::MSG_DBG
@@ -66,12 +68,12 @@ namespace AMDiS
       MPI_Comm_size(MPI_COMM_WORLD, &num_ranks);
       if (num_ranks > 1 && rank == 0) {
         out << "[0] ";
-        fmt::print(out, std::forward<Args>(args)...);
+        fmt::print(out, FWD(args)...);
       } else if (num_ranks == 1) {
-        fmt::print(out, std::forward<Args>(args)...);
+        fmt::print(out, FWD(args)...);
       }
 #else
-      fmt::print(out, std::forward<Args>(args)...);
+      fmt::print(out, FWD(args)...);
 #endif
       return out;
     }
@@ -89,7 +91,7 @@ namespace AMDiS
   template <class... Args>
   void msg(Args&&... args)
   {
-    Impl::msg(std::cout, std::forward<Args>(args)...) << std::endl;
+    Impl::msg(std::cout, FWD(args)...) << std::endl;
   }
 
 
@@ -103,7 +105,7 @@ namespace AMDiS
   template <class... Args>
   void msg_(Args&&... args)
   {
-    Impl::msg(std::cout, std::forward<Args>(args)...);
+    Impl::msg(std::cout, FWD(args)...);
   }
 
 
@@ -117,14 +119,14 @@ namespace AMDiS
   void error_exit(Args&&... args)
   {
 #ifdef AMDIS_NO_THROW
-    Impl::msg(std::cerr << "ERROR: ", std::forward<Args>(args)...) << std::endl;
+    Impl::msg(std::cerr << "ERROR: ", FWD(args)...) << std::endl;
     #ifndef NDEBUG
       assert(false);
     #else
       std::exit(EXIT_FAILURE);
     #endif
 #else
-    throw std::runtime_error( std::string("ERROR: ") + fmt::format(std::forward<Args>(args)...));
+    throw std::runtime_error( std::string("ERROR: ") + fmt::format(FWD(args)...));
 #endif
   }
 
@@ -141,14 +143,14 @@ namespace AMDiS
   template <class... Args>
   void test_exit(bool condition, Args&&... args)
   {
-    if (!condition) { error_exit(std::forward<Args>(args)...); }
+    if (!condition) { error_exit(FWD(args)...); }
   }
 
 
   template <class... Args>
   void warning(Args&&... args)
   {
-    Impl::msg(std::cout << "WARNING: ", std::forward<Args>(args)...) << std::endl;
+    Impl::msg(std::cout << "WARNING: ", FWD(args)...) << std::endl;
   }
 
 
@@ -161,7 +163,7 @@ namespace AMDiS
   template <class... Args>
   void test_warning(bool condition, Args&&... args)
   {
-    if (!condition) { warning(std::forward<Args>(args)...); }
+    if (!condition) { warning(FWD(args)...); }
   }
 
 
@@ -172,7 +174,7 @@ namespace AMDiS
    * \ref AMDIS_ENABLE_MSG_DBG is set to 1, otherwise the function is empty.
    **/
   template <class... Args>
-  void msg_dbg(Args&&... args) { msg(std::forward<Args>(args)...); }
+  void msg_dbg(Args&&... args) { msg(FWD(args)...); }
 
 
   /// \brief call assert_msg, in debug mode only
@@ -183,7 +185,7 @@ namespace AMDiS
   template <class... Args>
   void test_exit_dbg(bool condition, Args&&... args)
   {
-    test_exit(condition, std::forward<Args>(args)...);
+    test_exit(condition, FWD(args)...);
   }
 #else
   template <class... Args>
diff --git a/src/amdis/PeriodicBC.hpp b/src/amdis/PeriodicBC.hpp
index 23f4fb37..65541856 100644
--- a/src/amdis/PeriodicBC.hpp
+++ b/src/amdis/PeriodicBC.hpp
@@ -54,7 +54,7 @@ namespace AMDiS
   public:
     template <class BM>
     PeriodicBC(BM&& boundaryManager, BoundaryType id, FaceTrafo faceTrafo)
-      : Super(std::forward<BM>(boundaryManager), id)
+      : Super(FWD(boundaryManager), id)
       , faceTrafo_(std::move(faceTrafo))
     {}
 
diff --git a/src/amdis/PeriodicBC.inc.hpp b/src/amdis/PeriodicBC.inc.hpp
index ea08e9ed..a0c03627 100644
--- a/src/amdis/PeriodicBC.inc.hpp
+++ b/src/amdis/PeriodicBC.inc.hpp
@@ -202,7 +202,7 @@ coords(Node const& tree, std::vector<std::size_t> const& localIndices) const
     auto geometry = node.element().geometry();
 
     auto const& localInterpol = node.finiteElement().localInterpolation();
-    using FiniteElement = std::decay_t<decltype(node.finiteElement())>;
+    using FiniteElement = TYPEOF(node.finiteElement());
     using DomainType = typename FiniteElement::Traits::LocalBasisType::Traits::DomainType;
     using RangeType = typename FiniteElement::Traits::LocalBasisType::Traits::RangeType;
 
diff --git a/src/amdis/common/ClonablePtr.hpp b/src/amdis/common/ClonablePtr.hpp
new file mode 100644
index 00000000..23821f1c
--- /dev/null
+++ b/src/amdis/common/ClonablePtr.hpp
@@ -0,0 +1,127 @@
+#pragma once
+
+#include <memory>
+#include <utility>
+
+#include <amdis/common/Utility.hpp>
+
+namespace AMDiS
+{
+  // A pointer class that deletes only when owning the pointer
+  template <class T>
+  class ClonablePtr
+  {
+  private:
+    struct alloc_tag {}; ///< hidden helper struct, used by \ref make
+
+  public:
+    using Self = ClonablePtr;
+    using element_type = T;
+
+    /// Default constructor, creates a non-owned nullptr
+    ClonablePtr() = default;
+
+    /// Constructor from pointer. Can only be used via make method,
+    /// Transfers ownership.
+    ClonablePtr(owner<T>* p, alloc_tag) noexcept
+      : p(p)
+      , is_owner(true)
+    {}
+
+    /// Constructor from reference
+    explicit ClonablePtr(T& ref) noexcept
+      : p(&ref)
+      , is_owner(false)
+    {}
+
+    /// Constructor from std::unique_ptr
+    explicit ClonablePtr(std::unique_ptr<T>& ptr)
+      : p(ptr.release())
+      , is_owner(true)
+    {}
+
+    explicit ClonablePtr(std::unique_ptr<T>&& ptr)
+      : p(ptr.release())
+      , is_owner(true)
+    {}
+
+    /// Destructor, deletes in case of owner only
+    ~ClonablePtr() noexcept
+    {
+      if (is_owner)
+        delete p;
+    }
+
+    /// Copy constructor, creates a clone of the pointed to object
+    ClonablePtr(Self const& that) noexcept( std::is_nothrow_copy_constructible<T>::value )
+      : p(new T(*that.p))
+      , is_owner(true)
+    {}
+
+    /// Move constructor, copies the pointer only.
+    ClonablePtr(Self&& that) noexcept
+      : p(that.p)
+      , is_owner(that.is_owner)
+    {
+      that.p = nullptr;
+      that.is_owner = false;
+    }
+
+    /// Copy and move assignment operator, using the copy-and-swap idiom
+    Self& operator=(Self that) noexcept
+    {
+      swap(that);
+      return *this;
+    }
+
+    /// Factory method. creates a new Object of type T and stores the pointer.
+    template <class... Args>
+    static Self make(Args&&... args)
+      noexcept( std::is_nothrow_constructible<T, remove_cvref_t<Args>...>::value )
+    {
+      return {new T(FWD(args)...), Self::alloc_tag()};
+    }
+
+    /// Access-method by dereferencing
+    T& operator*() const noexcept
+    {
+      return *p;
+    }
+
+    /// Access-method by pointer access
+    T* operator->() const noexcept
+    {
+      return p;
+    }
+
+    /// retrieve the underlying pointer
+    T* get() const noexcept
+    {
+      return p;
+    }
+
+    /// Test whether pointer is NULL
+    operator bool() const noexcept
+    {
+      return !(p == NULL);
+    }
+
+    void swap(Self& that) noexcept
+    {
+      using std::swap;
+      swap(p, that.p);
+      swap(is_owner, that.is_owner);
+    }
+
+  private:
+    T* p = nullptr;		///< managed pointer
+    bool is_owner = false;	///< true, if class is owner of pointer, false otherwise
+  };
+
+  template <class T>
+  void swap(ClonablePtr<T>& a, ClonablePtr<T>& b) noexcept
+  {
+    a.swap(b);
+  }
+
+} // end namespace AMDiS
diff --git a/src/amdis/common/Concepts.hpp b/src/amdis/common/Concepts.hpp
index ed851525..6131f1cf 100644
--- a/src/amdis/common/Concepts.hpp
+++ b/src/amdis/common/Concepts.hpp
@@ -52,7 +52,7 @@ namespace AMDiS
       struct Callable
       {
         template <class F, class... Args>
-        auto requires_(F&& f, Args&&... args) -> decltype( f(std::forward<Args>(args)...));
+        auto requires_(F&& f, Args&&... args) -> decltype( f(FWD(args)...));
       };
 
       // idx[0]
diff --git a/src/amdis/common/ConcurrentCache.hpp b/src/amdis/common/ConcurrentCache.hpp
index 8e84f7b5..3f820916 100644
--- a/src/amdis/common/ConcurrentCache.hpp
+++ b/src/amdis/common/ConcurrentCache.hpp
@@ -125,8 +125,7 @@ namespace AMDiS
     template <class F, class... Args>
     static data_type const& get_or_init(key_type const& key, F&& f, Args&&... args)
     {
-      return impl(std::is_default_constructible<data_type>{},
-        key, std::forward<F>(f), std::forward<Args>(args)...);
+      return impl(std::is_default_constructible<data_type>{}, key, FWD(f), FWD(args)...);
     }
 
   private:
@@ -140,7 +139,7 @@ namespace AMDiS
       data_type empty;
       auto it = cached_data.emplace(key, std::move(empty));
       if (it.second) {
-        data_type data = f(key, std::forward<Args>(args)...);
+        data_type data = f(key, FWD(args)...);
         it.first->second = std::move(data);
       }
       return it.first->second;
@@ -157,7 +156,7 @@ namespace AMDiS
       if (it != cached_data.end())
         return it->second;
       else {
-        data_type data = f(key, std::forward<Args>(args)...);
+        data_type data = f(key, FWD(args)...);
         auto it = cached_data.emplace(key, std::move(data));
         return it.first->second;
       }
@@ -192,7 +191,7 @@ namespace AMDiS
         return it->second;
       else {
         read_lock.unlock();
-        data_type data = f(key, std::forward<Args>(args)...);
+        data_type data = f(key, FWD(args)...);
         std::unique_lock<mutex_type> write_lock(access_mutex);
         auto new_it = cached_data.emplace(key, std::move(data));
         return new_it.first->second;
@@ -224,7 +223,7 @@ namespace AMDiS
       static_assert(Dune::Std::is_callable<F(key_type, Args...), data_type>::value,
         "Functor F must have the signature data_type(key_type, Args...)");
 
-      return ConcurrentCache::get_or_init(key, std::forward<F>(f), std::forward<Args>(args)...);
+      return ConcurrentCache::get_or_init(key, FWD(f), FWD(args)...);
     }
   };
 
diff --git a/src/amdis/common/FieldTraits.hpp b/src/amdis/common/FieldTraits.hpp
new file mode 100644
index 00000000..b4560e0b
--- /dev/null
+++ b/src/amdis/common/FieldTraits.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <dune/common/ftraits.hh>
+
+#include <amdis/common/Utility.hpp>
+
+namespace AMDiS
+{
+  template <class... T>
+  struct CommonFieldTraits
+  {
+    using field_type = std::common_type_t<typename Dune::FieldTraits<T>::field_type...>;
+    using real_type = std::common_type_t<typename Dune::FieldTraits<T>::real_type...>;
+  };
+
+} // end namespace AMDiS
diff --git a/src/amdis/common/MultiTypeMatrix.hpp b/src/amdis/common/MultiTypeMatrix.hpp
index 2a512bda..392005ae 100644
--- a/src/amdis/common/MultiTypeMatrix.hpp
+++ b/src/amdis/common/MultiTypeMatrix.hpp
@@ -56,7 +56,7 @@ namespace AMDiS
     template <class... Rows_,
       REQUIRES( Concepts::Similar<Types<Rows...>, Types<Rows_...>> )>
     MultiTypeMatrix(Rows_&&... rows)
-      : Super(std::forward<Rows_>(rows)...)
+      : Super(FWD(rows)...)
     {}
 
     /// Default construction of tuple of FieldVectors
diff --git a/src/amdis/common/MultiTypeVector.hpp b/src/amdis/common/MultiTypeVector.hpp
index bfe4a24f..1f3e38f5 100644
--- a/src/amdis/common/MultiTypeVector.hpp
+++ b/src/amdis/common/MultiTypeVector.hpp
@@ -49,7 +49,7 @@ namespace AMDiS
     template <class... FV_,
       REQUIRES( Concepts::Similar<Types<FV...>, Types<FV_...>> )>
     MultiTypeVector(FV_&&... fv)
-      : Super(std::forward<FV_>(fv)...)
+      : Super(FWD(fv)...)
     {}
 
     /// Default construction of tuple of FieldVectors
diff --git a/src/amdis/common/ScalarTypes.hpp b/src/amdis/common/ScalarTypes.hpp
new file mode 100644
index 00000000..6a3ed614
--- /dev/null
+++ b/src/amdis/common/ScalarTypes.hpp
@@ -0,0 +1,41 @@
+#pragma once
+
+// std c++ headers
+#include <type_traits>
+#include <amdis/common/Utility.hpp>
+
+namespace AMDiS
+{
+  namespace Traits
+  {
+    template <class T>
+    struct IsIntegral
+        : public std::is_integral<remove_cvref_t<T>> {};
+
+    template <class T>
+    struct IsArithmetic
+        : public std::is_arithmetic<remove_cvref_t<T>> {};
+
+  } // end namespace traits
+
+  namespace Concepts
+  {
+    /** \addtogroup Concepts
+     *  @{
+     **/
+
+    /// \brief The types following the std type-trait \ref std::is_integral are
+    /// categorized as *integral types*.
+    template <class T>
+    constexpr bool Integral = Traits::IsIntegral<T>::value;
+
+    /// \brief The types following the std type-trait \ref std::is_arithmetic are
+    /// categorized as *arithmetic types*.
+    template <class T>
+    constexpr bool Arithmetic = Traits::IsArithmetic<T>::value;
+
+    /** @} **/
+
+  } // end namespace Concepts
+
+} // end namespace AMDiS
diff --git a/src/amdis/common/StaticSize.hpp b/src/amdis/common/StaticSize.hpp
index 81d5d48c..d1b399e1 100644
--- a/src/amdis/common/StaticSize.hpp
+++ b/src/amdis/common/StaticSize.hpp
@@ -79,10 +79,10 @@ namespace AMDiS
 
   /// Get the number of elements in a tuple / pair / array / ...
   template <class T>
-  constexpr std::size_t Size_v = Impl::SizeImpl<std::decay_t<T>>::value;
+  constexpr std::size_t Size_v = Impl::SizeImpl<remove_cvref_t<T>>::value;
 
   template <class T>
-  using Size_t = Impl::SizeImpl<std::decay_t<T>>;
+  using Size_t = Impl::SizeImpl<remove_cvref_t<T>>;
 
 
   namespace Impl
@@ -111,10 +111,10 @@ namespace AMDiS
 
   /// Get the number of rows in a fixed-size matrix
   template <class T>
-  constexpr std::size_t Rows_v = Impl::RowsImpl<std::decay_t<T>>::value;
+  constexpr std::size_t Rows_v = Impl::RowsImpl<remove_cvref_t<T>>::value;
 
   template <class T>
-  using Rows_t = Impl::RowsImpl<std::decay_t<T>>;
+  using Rows_t = Impl::RowsImpl<remove_cvref_t<T>>;
 
 
   namespace Impl
@@ -143,9 +143,9 @@ namespace AMDiS
 
   /// Get the number of columns in a fixed-size matrix
   template <class T>
-  constexpr std::size_t Cols_v = Impl::ColsImpl<std::decay_t<T>>::value;
+  constexpr std::size_t Cols_v = Impl::ColsImpl<remove_cvref_t<T>>::value;
 
   template <class T>
-  using Cols_t = Impl::ColsImpl<std::decay_t<T>>;
+  using Cols_t = Impl::ColsImpl<remove_cvref_t<T>>;
 
 } // end namespace AMDiS
diff --git a/src/amdis/common/Transposed.hpp b/src/amdis/common/Transposed.hpp
index 4778e95f..38920b96 100644
--- a/src/amdis/common/Transposed.hpp
+++ b/src/amdis/common/Transposed.hpp
@@ -8,7 +8,7 @@ namespace AMDiS
   template <class Matrix>
   class TransposedMatrix
   {
-    using RawMatrix = std::decay_t<Matrix>;
+    using RawMatrix = remove_cvref_t<Matrix>;
 
   public:
     using size_type = typename RawMatrix::size_type;
@@ -40,7 +40,7 @@ namespace AMDiS
   public:
     template <class M>
     TransposedMatrix(M&& matrix)
-      : matrix_(std::forward<M>(matrix))
+      : matrix_(FWD(matrix))
     {}
 
     ConstRowProxy operator[](size_type row) const
@@ -73,7 +73,7 @@ namespace AMDiS
   auto transposed(Matrix&& matrix)
   {
     using M = std::remove_reference_t<Matrix>;
-    return TransposedMatrix<M>{std::forward<Matrix>(matrix)};
+    return TransposedMatrix<M>{FWD(matrix)};
   }
 
 } // end namespace AMDiS
diff --git a/src/amdis/common/TypeTraits.hpp b/src/amdis/common/TypeTraits.hpp
index 47397712..315b6cc2 100644
--- a/src/amdis/common/TypeTraits.hpp
+++ b/src/amdis/common/TypeTraits.hpp
@@ -30,6 +30,16 @@ namespace AMDiS
   template <class T>
   using Underlying_t = typename Impl::UnderlyingType<T>::type;
 
+
+  /// Macro for forwarding universal references to obj
+  #define FWD(obj) std::forward<decltype(obj)>(obj)
+
+  /// A decay version of decltype, similar to GCCs __typeof__
+  #define TYPEOF(...) remove_cvref_t<decltype(__VA_ARGS__)>
+
+  /// Extract the static value of an integral_constant variable
+  #define VALUE(...) TYPEOF(__VA_ARGS__)::value
+
   // ---------------------------------------------------------------------------
 
   /// A variadic type list
diff --git a/src/amdis/common/Utility.hpp b/src/amdis/common/Utility.hpp
new file mode 100644
index 00000000..49fc8203
--- /dev/null
+++ b/src/amdis/common/Utility.hpp
@@ -0,0 +1,130 @@
+#pragma once
+
+#include <memory>
+#include <type_traits>
+#include <vector>
+
+#if AMDIS_HAS_CXX_CONSTEXPR_IF
+#define IF_CONSTEXPR if constexpr
+#else
+#define IF_CONSTEXPR if
+#endif
+
+namespace AMDiS
+{
+  /// \brief Remove cv and ref qualifiers of type T.
+  /**
+   * If the type T is a reference type, provides the member typedef type which
+   * is the type referred to by T with its topmost cv-qualifiers removed.
+   * Otherwise type is T with its topmost cv-qualifiers removed.
+   *
+   * Note: This is a backport of c++20 std::remove_cvref
+   **/
+  template< class T >
+  struct remove_cvref
+  {
+    using type = std::remove_cv_t<std::remove_reference_t<T>>;
+  };
+
+  /// Helper alias template for \ref remove_cvref
+  template< class T >
+  using remove_cvref_t = typename remove_cvref<T>::type;
+
+
+  namespace Impl
+  {
+    template <class T>
+    struct UnderlyingType
+    {
+      using type = remove_cvref_t<T>;
+    };
+
+    template <class T>
+    struct UnderlyingType<std::reference_wrapper<T>>
+    {
+      using type = std::remove_cv_t<T>;
+    };
+  }
+
+  /// \brief strip reference_wrapper, const, volatile, and references from type T
+  template <class T>
+  using Underlying_t = typename Impl::UnderlyingType<T>::type;
+
+
+  /// Macro for forwarding universal references to obj
+  #define FWD(obj) std::forward<decltype(obj)>(obj)
+
+  /// A decay version of decltype, similar to GCCs __typeof__
+  #define TYPEOF(...) remove_cvref_t<decltype(__VA_ARGS__)>
+
+  /// Extract the static value of an integral_constant variable
+  #define VALUE(...) TYPEOF(__VA_ARGS__)::value
+
+  /// Create a unique_ptr by copy/move construction
+  template <class Obj>
+  auto makeUniquePtr(Obj&& obj)
+  {
+    return std::make_unique<TYPEOF(obj)>(FWD(obj));
+  }
+
+  // ---------------------------------------------------------------------------
+
+  // base template for tuple size, must implement a static value member
+  template <class TupleType>
+  struct TupleSize;
+
+  // utility constant returning the value of the tuple size
+  template <class TupleType>
+  constexpr std::size_t TupleSize_v = TupleSize<TupleType>::value;
+
+
+  // base template for retrieving the tuple element type, must implement the type member `type`
+  template <size_t I, class TupleType>
+  struct TupleElement;
+
+  // base template for retrieving the tuple element type
+  template <size_t I, class TupleType>
+  using TupleElement_t = typename TupleElement<I, TupleType>::type;
+
+
+  /// A variadic type list
+  template <class... Ts>
+  struct Types {};
+
+  template <class... Ts>
+  using Types_t = Types<remove_cvref_t<Ts>...>;
+
+
+  template <class... T>
+  struct TupleSize<Types<T...>>
+    : std::integral_constant<std::size_t, sizeof...(T)> {};
+
+  template <size_t I, class Head, class... Tail>
+  struct TupleElement<I, Types<Head, Tail...>>
+  {
+    using type = typename TupleElement<I-1, Types<Tail...>>::type;
+  };
+
+  template <class Head, class... Tail>
+  struct TupleElement<0, Types<Head, Tail...>>
+  {
+    using type = Head;
+  };
+
+
+  /// Alias that indicates ownership of resources
+  template <class T>
+  using owner = T;
+
+
+  // ---------------------------------------------------------------------------
+
+
+  /// generalization of get<tuple>, get<array> for vectors
+  template <std::size_t I, class T, class A>
+  T const& get(std::vector<T,A> const& vec)
+  {
+      return vec[I];
+  }
+
+} // end namespace AMDiS
diff --git a/src/amdis/common/ValueCategory.hpp b/src/amdis/common/ValueCategory.hpp
index 3c1b61c3..71d72db1 100644
--- a/src/amdis/common/ValueCategory.hpp
+++ b/src/amdis/common/ValueCategory.hpp
@@ -18,7 +18,7 @@ namespace AMDiS
   };
 
   template <class T>
-  using ValueCategory_t = typename ValueCategory<std::decay_t<T>>::type;
+  using ValueCategory_t = typename ValueCategory<remove_cvref_t<T>>::type;
 
   template <class T>
   struct ValueCategory<T, std::enable_if_t< std::is_arithmetic<T>::value >>
diff --git a/src/amdis/gridfunctions/AnalyticGridFunction.hpp b/src/amdis/gridfunctions/AnalyticGridFunction.hpp
index 53303820..c0994d4f 100644
--- a/src/amdis/gridfunctions/AnalyticGridFunction.hpp
+++ b/src/amdis/gridfunctions/AnalyticGridFunction.hpp
@@ -129,7 +129,7 @@ namespace AMDiS
   public:
     using EntitySet = Dune::Functions::GridViewEntitySet<GridView, 0>;
     using Domain = typename EntitySet::GlobalCoordinate;
-    using Range = std::decay_t<std::result_of_t<Function(Domain)>>;
+    using Range = remove_cvref_t<std::result_of_t<Function(Domain)>>;
 
     enum { hasDerivative = true };
 
diff --git a/src/amdis/gridfunctions/DOFVectorView.hpp b/src/amdis/gridfunctions/DOFVectorView.hpp
index 55f0bf74..f95677a9 100644
--- a/src/amdis/gridfunctions/DOFVectorView.hpp
+++ b/src/amdis/gridfunctions/DOFVectorView.hpp
@@ -44,10 +44,9 @@ namespace AMDiS
       auto const& basis = this->basis();
       auto const& treePath = this->treePath();
 
-      auto&& gridFct = makeGridFunction(std::forward<Expr>(expr), basis.gridView());
+      auto&& gridFct = makeGridFunction(FWD(expr), basis.gridView());
 
-      Dune::Functions::interpolate(basis, treePath, coefficients(),
-        std::forward<decltype(gridFct)>(gridFct));
+      Dune::Functions::interpolate(basis, treePath, coefficients(), FWD(gridFct));
     }
 
     /// \brief Interpolation of GridFunction to DOFVector
@@ -66,7 +65,7 @@ namespace AMDiS
       // create temporary copy of data
       DOFVector<GB,VT> tmp(coefficients());
       Self tmpView{tmp, this->treePath()};
-      tmpView.interpolate_noalias(std::forward<Expr>(expr));
+      tmpView.interpolate_noalias(FWD(expr));
 
       // move data from temporary vector into stored DOFVector
       coefficients().vector() = std::move(tmp.vector());
diff --git a/src/amdis/gridfunctions/DerivativeGridFunction.hpp b/src/amdis/gridfunctions/DerivativeGridFunction.hpp
index f1b2abeb..19693c8d 100644
--- a/src/amdis/gridfunctions/DerivativeGridFunction.hpp
+++ b/src/amdis/gridfunctions/DerivativeGridFunction.hpp
@@ -29,7 +29,7 @@ namespace AMDiS
     using GridFctDomain = typename GridFunction::Domain;
     using RawSignature = typename Dune::Functions::SignatureTraits<GridFctRange(GridFctDomain)>::RawSignature;
     using DerivativeTraits = Dune::Functions::DefaultDerivativeTraits<RawSignature>;
-    using LocalFunction = std::decay_t<decltype(derivative(localFunction(std::declval<GridFunction>())))>;
+    using LocalFunction = TYPEOF( derivative(localFunction(std::declval<GridFunction>())) ) ;
 
     enum { hasDerivative = false };
 
diff --git a/src/amdis/gridfunctions/DiscreteFunction.inc.hpp b/src/amdis/gridfunctions/DiscreteFunction.inc.hpp
index 069e67c6..52c47b3e 100644
--- a/src/amdis/gridfunctions/DiscreteFunction.inc.hpp
+++ b/src/amdis/gridfunctions/DiscreteFunction.inc.hpp
@@ -152,8 +152,7 @@ LocalFunction::operator()(Domain const& x) const
     auto&& fe = node.finiteElement();
     auto&& localBasis = fe.localBasis();
 
-    using Node = std::decay_t<decltype(node)>;
-    NodeCache<Node> localBasisCache(localBasis);
+    NodeCache<TYPEOF(node)> localBasisCache(localBasis);
     auto const& shapeFunctionValues = localBasisCache.evaluateFunction(localView_.element().type(),x);
 
     // Get range entry associated to this node
@@ -204,8 +203,7 @@ GradientLocalFunction::operator()(Domain const& x) const
     auto&& fe = node.finiteElement();
     auto&& localBasis = fe.localBasis();
 
-    using Node = std::decay_t<decltype(node)>;
-    NodeCache<Node> localBasisCache(localBasis);
+    NodeCache<TYPEOF(node)> localBasisCache(localBasis);
     auto const& referenceGradients = localBasisCache.evaluateJacobian(localView_.element().type(),x);
 
     // The transposed inverse Jacobian of the map from the reference element to the element
diff --git a/src/amdis/gridfunctions/FunctorGridFunction.hpp b/src/amdis/gridfunctions/FunctorGridFunction.hpp
index 99688cf2..566a6460 100644
--- a/src/amdis/gridfunctions/FunctorGridFunction.hpp
+++ b/src/amdis/gridfunctions/FunctorGridFunction.hpp
@@ -67,7 +67,7 @@ namespace AMDiS
     template <class... GridFcts>
     FunctorLocalFunction(Functor const& fct, GridFcts&&... gridFcts)
       : fct_{fct}
-      , localFcts_{std::forward<GridFcts>(gridFcts)...}
+      , localFcts_{FWD(gridFcts)...}
     {}
 
     /// Calls \ref bind for all localFunctions
@@ -203,9 +203,9 @@ namespace AMDiS
 
   private:
     template <class GridFct>
-    using LocalFct = std::decay_t<decltype(localFunction(std::declval<GridFct>()))>;
+    using LocalFct = TYPEOF( localFunction(std::declval<GridFct>()) );
 
-    using RawRange = std::decay_t<Range>;
+    using RawRange = remove_cvref_t<Range>;
     using LocalDomain = typename EntitySet::LocalCoordinate;
 
   public:
@@ -215,7 +215,7 @@ namespace AMDiS
     template <class... GridFcts>
     explicit FunctorGridFunction(Functor const& fct, GridFcts&&... gridFcts)
       : fct_{fct}
-      , gridFcts_{std::forward<GridFcts>(gridFcts)...}
+      , gridFcts_{FWD(gridFcts)...}
     {}
 
     /// Applies the functor to the evaluated gridfunctions
@@ -288,7 +288,7 @@ namespace AMDiS
     template <class... PreGridFcts>
     explicit FunctorPreGridFunction(Functor const& fct, PreGridFcts&&... pgfs)
       : fct_{fct}
-      , preGridFcts_{std::forward<PreGridFcts>(pgfs)...}
+      , preGridFcts_{FWD(pgfs)...}
     {}
 
   private:
@@ -320,7 +320,7 @@ namespace AMDiS
   template <class Functor, class... PreGridFcts>
   auto invokeAtQP(Functor const& f, PreGridFcts&&... gridFcts)
   {
-    return FunctorPreGridFunction<Functor, std::decay_t<PreGridFcts>...>{f, std::forward<PreGridFcts>(gridFcts)...};
+    return FunctorPreGridFunction<Functor, TYPEOF(gridFcts)...>{f, FWD(gridFcts)...};
   }
 
 } // end namespace AMDiS
diff --git a/src/amdis/gridfunctions/GridFunctionConcepts.hpp b/src/amdis/gridfunctions/GridFunctionConcepts.hpp
index ac073736..d9357bd0 100644
--- a/src/amdis/gridfunctions/GridFunctionConcepts.hpp
+++ b/src/amdis/gridfunctions/GridFunctionConcepts.hpp
@@ -120,8 +120,8 @@ namespace AMDiS
     /// can be converted to a GridFunction, or is already a GridFunction.
     template <class... GFs>
     constexpr bool AnyGridFunction =
-      any_of_v<GridFunction<std::decay_t<GFs>>...> ||
-      any_of_v<Traits::IsPreGridFunction<std::decay_t<GFs>>::value...>;
+      any_of_v<GridFunction<remove_cvref_t<GFs>>...> ||
+      any_of_v<Traits::IsPreGridFunction<remove_cvref_t<GFs>>::value...>;
 
     /** @} **/
 
diff --git a/src/amdis/gridfunctions/OperationsGridFunction.hpp b/src/amdis/gridfunctions/OperationsGridFunction.hpp
index 425d5d68..18001485 100644
--- a/src/amdis/gridfunctions/OperationsGridFunction.hpp
+++ b/src/amdis/gridfunctions/OperationsGridFunction.hpp
@@ -20,7 +20,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<Lhs>)>
   auto operator-(Lhs&& lhs)
   {
-    return invokeAtQP(Operation::Negate{}, std::forward<Lhs>(lhs));
+    return invokeAtQP(Operation::Negate{}, FWD(lhs));
   }
 
   /// \brief Applies \ref Operation::Plus to GridFunctions. \relates FunctorGridFunction
@@ -28,7 +28,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<Lhs,Rhs>)>
   auto operator+(Lhs&& lhs, Rhs&& rhs)
   {
-    return invokeAtQP(Operation::Plus{}, std::forward<Lhs>(lhs), std::forward<Rhs>(rhs));
+    return invokeAtQP(Operation::Plus{}, FWD(lhs), FWD(rhs));
   }
 
   /// \brief Applies \ref Operation::Minus to GridFunctions. \relates FunctorGridFunction
@@ -36,7 +36,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<Lhs,Rhs>)>
   auto operator-(Lhs&& lhs, Rhs&& rhs)
   {
-    return invokeAtQP(Operation::Minus{}, std::forward<Lhs>(lhs), std::forward<Rhs>(rhs));
+    return invokeAtQP(Operation::Minus{}, FWD(lhs), FWD(rhs));
   }
 
   /// \brief Applies \ref Operation::Multiplies to GridFunctions. \relates FunctorGridFunction
@@ -44,7 +44,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<Lhs,Rhs>)>
   auto operator*(Lhs&& lhs, Rhs&& rhs)
   {
-    return invokeAtQP(Operation::Multiplies{}, std::forward<Lhs>(lhs), std::forward<Rhs>(rhs));
+    return invokeAtQP(Operation::Multiplies{}, FWD(lhs), FWD(rhs));
   }
 
   namespace Impl
@@ -53,14 +53,14 @@ namespace AMDiS
       REQUIRES(Concepts::ConstantToGridFunction<Value>)>
     auto divideAtQP(Lhs&& lhs, Value value)
     {
-      return invokeAtQP(Operation::Multiplies{}, std::forward<Lhs>(lhs), 1.0/value);
+      return invokeAtQP(Operation::Multiplies{}, FWD(lhs), 1.0/value);
     }
 
     template <class Lhs, class Rhs,
-      REQUIRES(not Concepts::ConstantToGridFunction<std::decay_t<Rhs>>)>
+      REQUIRES(not Concepts::ConstantToGridFunction<remove_cvref_t<Rhs>>)>
     auto divideAtQP(Lhs&& lhs, Rhs&& rhs)
     {
-      return invokeAtQP(Operation::Divides{}, std::forward<Lhs>(lhs), std::forward<Rhs>(rhs));
+      return invokeAtQP(Operation::Divides{}, FWD(lhs), FWD(rhs));
     }
   }
 
@@ -69,7 +69,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<Lhs,Rhs>)>
   auto operator/(Lhs&& lhs, Rhs&& rhs)
   {
-    return Impl::divideAtQP(std::forward<Lhs>(lhs), std::forward<Rhs>(rhs));
+    return Impl::divideAtQP(FWD(lhs), FWD(rhs));
   }
 
 
@@ -78,7 +78,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<Lhs,Rhs>)>
   auto max(Lhs&& lhs, Rhs&& rhs)
   {
-    return invokeAtQP(Operation::Max{}, std::forward<Lhs>(lhs), std::forward<Rhs>(rhs));
+    return invokeAtQP(Operation::Max{}, FWD(lhs), FWD(rhs));
   }
 
   /// \brief Applies \ref Operation::Min to GridFunctions. \relates FunctorGridFunction
@@ -86,7 +86,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<Lhs,Rhs>)>
   auto min(Lhs&& lhs, Rhs&& rhs)
   {
-    return invokeAtQP(Operation::Min{}, std::forward<Lhs>(lhs), std::forward<Rhs>(rhs));
+    return invokeAtQP(Operation::Min{}, FWD(lhs), FWD(rhs));
   }
 
   /// \brief Applies \ref Operation::AbsMax to GridFunctions. \relates FunctorGridFunction
@@ -94,7 +94,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<Lhs,Rhs>)>
   auto abs_max(Lhs&& lhs, Rhs&& rhs)
   {
-    return invokeAtQP(Operation::AbsMax{}, std::forward<Lhs>(lhs), std::forward<Rhs>(rhs));
+    return invokeAtQP(Operation::AbsMax{}, FWD(lhs), FWD(rhs));
   }
 
   /// \brief Applies \ref Operation::AbsMin to GridFunctions. \relates FunctorGridFunction
@@ -102,7 +102,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<Lhs,Rhs>)>
   auto abs_min(Lhs&& lhs, Rhs&& rhs)
   {
-    return invokeAtQP(Operation::AbsMin{}, std::forward<Lhs>(lhs), std::forward<Rhs>(rhs));
+    return invokeAtQP(Operation::AbsMin{}, FWD(lhs), FWD(rhs));
   }
 
   /// \brief Applies \ref Operation::Clamp to GridFunction. \relates FunctorGridFunction
@@ -110,7 +110,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<V>)>
   auto clamp(V&& v, T const& lo, T const& hi)
   {
-    return invokeAtQP(Operation::Clamp<T>{lo,hi}, std::forward<V>(v));
+    return invokeAtQP(Operation::Clamp<T>{lo,hi}, FWD(v));
   }
 
   /// \brief Applies \ref Operation::Sqr to GridFunction. \relates FunctorGridFunction
@@ -118,7 +118,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<T>)>
   auto sqr(T&& value)
   {
-    return invokeAtQP(Operation::Sqr{}, std::forward<T>(value));
+    return invokeAtQP(Operation::Sqr{}, FWD(value));
   }
 
   /// \brief Applies \ref Operation::Pow<p> to GridFunction. \relates FunctorGridFunction
@@ -126,7 +126,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<T>)>
   auto pow(T&& value)
   {
-    return invokeAtQP(Operation::Pow<p>{}, std::forward<T>(value));
+    return invokeAtQP(Operation::Pow<p>{}, FWD(value));
   }
 
   /// \brief Applies \ref Operation::Pow_ to GridFunction. \relates FunctorGridFunction
@@ -134,7 +134,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<T>)>
   auto pow(T&& value, int p)
   {
-    return invokeAtQP(Operation::Pow_{p}, std::forward<T>(value));
+    return invokeAtQP(Operation::Pow_{p}, FWD(value));
   }
 
   /// \brief Applies \ref Operation::Get<I> to GridFunction. \relates FunctorGridFunction
@@ -142,7 +142,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<T>)>
   auto get(T&& value)
   {
-    return invokeAtQP(Operation::Get<I>{}, std::forward<T>(value));
+    return invokeAtQP(Operation::Get<I>{}, FWD(value));
   }
 
   /// \brief Applies \ref Operation::Get_ to GridFunction. \relates FunctorGridFunction
@@ -150,7 +150,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<T>)>
   auto get(T&& value, std::size_t i)
   {
-    return invokeAtQP(Operation::Get_{i}, std::forward<T>(value));
+    return invokeAtQP(Operation::Get_{i}, FWD(value));
   }
 
   // @}
@@ -163,7 +163,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<Vec>)>
   auto sum(Vec&& vec)
   {
-    return invokeAtQP([](auto const& v) { return sum(v); }, std::forward<Vec>(vec));
+    return invokeAtQP([](auto const& v) { return sum(v); }, FWD(vec));
   }
 
   /// \brief Applies \ref Operation::UnaryDot to a vector-valued GridFunction. \relates FunctorGridFunction
@@ -171,7 +171,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<Vec>)>
   auto unary_dot(Vec&& vec)
   {
-    return invokeAtQP(Operation::UnaryDot{}, std::forward<Vec>(vec));
+    return invokeAtQP(Operation::UnaryDot{}, FWD(vec));
   }
 
   /// \brief Applies a \ref one_norm() functor to a vector-valued GridFunction. \relates FunctorGridFunction
@@ -179,7 +179,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<Vec>)>
   auto one_norm(Vec&& vec)
   {
-    return invokeAtQP([](auto const& v) { return one_norm(v); }, std::forward<Vec>(vec));
+    return invokeAtQP([](auto const& v) { return one_norm(v); }, FWD(vec));
   }
 
   /// \brief Applies \ref Operation::TwoNorm to a vector-valued GridFunction. \relates FunctorGridFunction
@@ -187,7 +187,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<Vec>)>
   auto two_norm(Vec&& vec)
   {
-    return invokeAtQP(Operation::TwoNorm{}, std::forward<Vec>(vec));
+    return invokeAtQP(Operation::TwoNorm{}, FWD(vec));
   }
 
   /// \brief Applies a \ref p_norm() functor to a vector-valued GridFunction. \relates FunctorGridFunction
@@ -195,7 +195,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<Vec>)>
   auto p_norm(Vec&& vec)
   {
-    return invokeAtQP([](auto const& v) { return p_norm<p>(v); }, std::forward<Vec>(vec));
+    return invokeAtQP([](auto const& v) { return p_norm<p>(v); }, FWD(vec));
   }
 
   /// \brief Applies a \ref infty_norm() functor to a vector-valued GridFunction. \relates FunctorGridFunction
@@ -203,7 +203,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<Vec>)>
   auto infty_norm(Vec&& vec)
   {
-    return invokeAtQP([](auto const& v) { return infty_norm(v); }, std::forward<Vec>(vec));
+    return invokeAtQP([](auto const& v) { return infty_norm(v); }, FWD(vec));
   }
 
   /// \brief Applies \ref Operation::Trans to a matrix-valued GridFunction.\relates FunctorGridFunction
@@ -211,7 +211,7 @@ namespace AMDiS
     REQUIRES(Concepts::AnyGridFunction<Mat>)>
   auto trans(Mat&& mat)
   {
-    return invokeAtQP(Operation::Trans{}, std::forward<Mat>(mat));
+    return invokeAtQP(Operation::Trans{}, FWD(mat));
   }
 
   // @}
@@ -226,7 +226,7 @@ namespace AMDiS
   auto dot(Lhs&& lhs, Rhs&& rhs)
   {
     return invokeAtQP(Operation::Dot{},
-      std::forward<Lhs>(lhs), std::forward<Rhs>(rhs));
+      FWD(lhs), FWD(rhs));
   }
 
   /// \brief Applies a distance-functor to two vector-valued GridFunctions.\relates FunctorGridFunction
@@ -236,7 +236,7 @@ namespace AMDiS
   {
     using namespace Operation;
     return invokeAtQP(compose(TwoNorm{}, Minus{}),
-      std::forward<Lhs>(lhs), std::forward<Rhs>(rhs));
+      FWD(lhs), FWD(rhs));
   }
 
   /// \brief Applies an \ref outer() functor to two vector-valued GridFunctions. \relates FunctorGridFunction
@@ -245,7 +245,7 @@ namespace AMDiS
   auto outer(Lhs&& lhs, Rhs&& rhs)
   {
     return invokeAtQP([](auto const& v, auto const& w) { return outer(v,w); },
-      std::forward<Lhs>(lhs), std::forward<Rhs>(rhs));
+      FWD(lhs), FWD(rhs));
   }
 
   // @}
diff --git a/src/amdis/operations/Basic.hpp b/src/amdis/operations/Basic.hpp
index ed95863a..304023d1 100644
--- a/src/amdis/operations/Basic.hpp
+++ b/src/amdis/operations/Basic.hpp
@@ -117,7 +117,7 @@ namespace AMDiS
       template <class... Ts>
       constexpr auto&& operator()(Ts&&... args) const
       {
-        return std::get<I>(std::forward_as_tuple(std::forward<Ts>(args)...));
+        return std::get<I>(std::forward_as_tuple(FWD(args)...));
       }
     };
 
diff --git a/src/amdis/operations/Composer.hpp b/src/amdis/operations/Composer.hpp
index 2e1338f0..586cc45b 100644
--- a/src/amdis/operations/Composer.hpp
+++ b/src/amdis/operations/Composer.hpp
@@ -32,8 +32,8 @@ namespace AMDiS
       template <class F_, class... Gs_,
         REQUIRES( Concepts::Similar<Types<F,Gs...>, Types<F_,Gs_...>>) >
       constexpr Composer(F_&& f, Gs_&&... gs)
-        : f_(std::forward<F_>(f))
-        , gs_(std::forward<Gs_>(gs)...)
+        : f_(FWD(f))
+        , gs_(FWD(gs)...)
       {}
 
       template <class... Ts>
@@ -56,7 +56,7 @@ namespace AMDiS
       template <class F_, class... Gs_>
       static constexpr type build(F_&& f, Gs_&&... gs)
       {
-        return type{std::forward<F_>(f), std::forward<Gs_>(gs)...};
+        return type{FWD(f), FWD(gs)...};
       }
     };
 #endif
@@ -65,8 +65,7 @@ namespace AMDiS
     template <class F, class... Gs>
     constexpr auto compose(F&& f, Gs&&... gs)
     {
-      return ComposerBuilder<std::decay_t<F>, std::decay_t<Gs>...>::build(
-        std::forward<F>(f), std::forward<Gs>(gs)...);
+      return ComposerBuilder<TYPEOF(f), TYPEOF(gs)...>::build(FWD(f), FWD(gs)...);
     }
 
     // Polynomial order or composed function combines the orders of the sub-functions
@@ -97,7 +96,7 @@ namespace AMDiS
       template <class F_>
       static constexpr F build(F_&& f)
       {
-        return F{std::forward<F_>(f)};
+        return F{FWD(f)};
       }
     };
 #endif
diff --git a/src/amdis/typetree/RangeType.hpp b/src/amdis/typetree/RangeType.hpp
index 0e36925e..38b2ecec 100644
--- a/src/amdis/typetree/RangeType.hpp
+++ b/src/amdis/typetree/RangeType.hpp
@@ -43,7 +43,7 @@ namespace AMDiS
     {
       using LocalBasis = typename Node::FiniteElement::Traits::LocalBasisType;
       using T = typename LocalBasis::Traits::RangeType;
-      using type = std::decay_t<decltype(std::declval<R>() * std::declval<T>())>;
+      using type = remove_cvref_t<decltype(std::declval<R>() * std::declval<T>())>;
     };
 
     // Power node
diff --git a/src/amdis/typetree/Traversal.hpp b/src/amdis/typetree/Traversal.hpp
index 3a02e742..a0255eb3 100644
--- a/src/amdis/typetree/Traversal.hpp
+++ b/src/amdis/typetree/Traversal.hpp
@@ -5,6 +5,7 @@
 #include <dune/typetree/visitor.hh>
 
 #include <amdis/common/Loops.hpp>
+#include <amdis/common/TypeTraits.hpp>
 
 namespace AMDiS
 {
@@ -78,28 +79,28 @@ namespace AMDiS
       using Node = std::remove_reference_t<N>;
       using Visitor = std::remove_reference_t<V>;
 
-      v.pre(std::forward<N>(n),tp);
+      v.pre(FWD(n),tp);
 
       auto const deg = hybridDegree(NodeTag{}, n);
       forEach(Dune::range(deg), [&](auto const _k)
       {
         // always call beforeChild(), regardless of the value of visit
-        v.beforeChild(std::forward<N>(n),n.child(_k),tp,_k);
+        v.beforeChild(FWD(n),n.child(_k),tp,_k);
 
         // descend to child
         using C = typename HybridChildType<Node, decltype(_k)>::type;
         const bool visit = Visitor::template VisitChild<Node,C,TreePath>::value;
-        TraverseTree<Dune::TypeTree::NodeTag<C>,visit>::apply(n.child(_k),std::forward<V>(v),push_back(tp, _k));
+        TraverseTree<Dune::TypeTree::NodeTag<C>,visit>::apply(n.child(_k),FWD(v),push_back(tp, _k));
 
         // always call afterChild(), regardless of the value of visit
-        v.afterChild(std::forward<N>(n),n.child(_k),tp,_k);
+        v.afterChild(FWD(n),n.child(_k),tp,_k);
 
         // if this is not the last child, call infix callback
         if (notLastChild(_k, deg))
-          v.in(std::forward<N>(n),tp);
+          v.in(FWD(n),tp);
       });
 
-      v.post(std::forward<N>(n),tp);
+      v.post(FWD(n),tp);
     }
   };
 
@@ -110,7 +111,7 @@ namespace AMDiS
     template <typename N, typename V, typename TreePath>
     static void apply(N&& n, V&& v, TreePath const& tp)
     {
-      v.leaf(std::forward<N>(n),tp);
+      v.leaf(FWD(n),tp);
     }
   };
 
@@ -131,7 +132,7 @@ namespace AMDiS
     using Node = std::remove_reference_t<Tree>;
     using NodeTag = Dune::TypeTree::NodeTag<Node>;
     using TreePath = Dune::TypeTree::HybridTreePath<>;
-    TraverseTree<NodeTag>::apply(std::forward<Tree>(tree), std::forward<Visitor>(visitor), TreePath{});
+    TraverseTree<NodeTag>::apply(FWD(tree), FWD(visitor), TreePath{});
   }
 
 } // end namespace AMDiS
-- 
GitLab