From 09ec4971abfa99db7ee91b394bc0db1d0241ded3 Mon Sep 17 00:00:00 2001
From: dedner <a.s.dedner@warwick.ac.uk>
Date: Mon, 27 Jul 2015 18:32:02 +0100
Subject: [PATCH] Improve the className function to provide more information

---
 dune/common/classname.hh          | 32 ++++++++---------
 dune/common/test/CMakeLists.txt   |  2 ++
 dune/common/test/Makefile.am      |  3 ++
 dune/common/test/classnametest.cc | 58 +++++++++++++++++++++++++++++++
 4 files changed, 78 insertions(+), 17 deletions(-)
 create mode 100644 dune/common/test/classnametest.cc

diff --git a/dune/common/classname.hh b/dune/common/classname.hh
index 0bc7d8b80..57e0a9a21 100644
--- a/dune/common/classname.hh
+++ b/dune/common/classname.hh
@@ -18,11 +18,12 @@
 
 namespace Dune {
 
-  /** \brief Provide the demangled class name of a given object as a string */
+  /** \brief Provide the demangled class name of a type T as a string */
   template <class T>
-  std::string className ( T &t )
+  std::string className ()
   {
-    std::string className = typeid( t ).name();
+    typedef typename std::remove_reference<T>::type TR;
+    std::string className = typeid( TR ).name();
 #if HAVE_CXA_DEMANGLE
     int status;
     char *demangled = abi::__cxa_demangle( className.c_str(), 0, 0, &status );
@@ -32,26 +33,23 @@ namespace Dune {
       std::free( demangled );
     }
 #endif // #if HAVE_CXA_DEMANGLE
+    if (std::is_const<TR>::value)
+        className += " const";
+    if (std::is_volatile<TR>::value)
+        className += " volatile";
+    if (std::is_lvalue_reference<T>::value)
+        className += "&";
+    else if (std::is_rvalue_reference<T>::value)
+        className += "&&";
     return className;
   }
 
-  /** \brief Provide the demangled class name of a type T as a string */
+  /** \brief Provide the demangled class name of a given object as a string */
   template <class T>
-  std::string className ()
+  std::string className ( T& t )
   {
-    std::string className = typeid( T ).name();
-#if HAVE_CXA_DEMANGLE
-    int status;
-    char *demangled = abi::__cxa_demangle( className.c_str(), 0, 0, &status );
-    if( demangled )
-    {
-      className = demangled;
-      std::free( demangled );
-    }
-#endif // #if HAVE_CXA_DEMANGLE
-    return className;
+    return className<T>();
   }
-
 } // namespace Dune
 
 #endif  // DUNE_CLASSNAME_HH
diff --git a/dune/common/test/CMakeLists.txt b/dune/common/test/CMakeLists.txt
index 05d2d0b55..2d791a9e6 100644
--- a/dune/common/test/CMakeLists.txt
+++ b/dune/common/test/CMakeLists.txt
@@ -6,6 +6,7 @@ set(TESTS
     bitsetvectortest
     calloncetest
     check_fvector_size
+    classnametest
     conversiontest
     diagonalmatrixtest
     dynmatrixtest
@@ -68,6 +69,7 @@ add_executable("check_fvector_size_fail1" EXCLUDE_FROM_ALL check_fvector_size_fa
 set_target_properties(check_fvector_size_fail1 PROPERTIES COMPILE_FLAGS "-DDIM=1")
 add_executable("check_fvector_size_fail2" EXCLUDE_FROM_ALL check_fvector_size_fail.cc)
 set_target_properties(check_fvector_size_fail2 PROPERTIES COMPILE_FLAGS "-DDIM=3")
+add_executable("classnametest" classnametest.cc)
 add_executable("conversiontest" conversiontest.cc)
 
 add_executable("dynmatrixtest" dynmatrixtest.cc)
diff --git a/dune/common/test/Makefile.am b/dune/common/test/Makefile.am
index 00a21fb7b..07276bd00 100644
--- a/dune/common/test/Makefile.am
+++ b/dune/common/test/Makefile.am
@@ -7,6 +7,7 @@ TESTPROGS = \
     bitsetvectortest \
     calloncetest \
     check_fvector_size \
+    classnametest \
     conversiontest \
     diagonalmatrixtest \
     dynmatrixtest \
@@ -104,6 +105,8 @@ check_fvector_size_fail2_CPPFLAGS = $(AM_CPPFLAGS) -DDIM=3
 
 check_fvector_size_SOURCES = check_fvector_size.cc
 
+classnametest_SOURCES = classnametest.cc
+
 conversiontest_SOURCES = conversiontest.cc
 
 diagonalmatrixtest_SOURCES = diagonalmatrixtest.cc
diff --git a/dune/common/test/classnametest.cc b/dune/common/test/classnametest.cc
new file mode 100644
index 000000000..be61bc6d2
--- /dev/null
+++ b/dune/common/test/classnametest.cc
@@ -0,0 +1,58 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <dune/common/fvector.hh>
+#include <dune/common/classname.hh>
+#include <iostream>
+#include <complex>
+
+
+using Dune::FieldVector;
+using std::complex;
+
+int main()
+{
+  try {
+    std::cout << "First three simple class names extracted from variables:" << std::endl;
+    FieldVector<int, 3> xi;
+    std::cout << className(xi) << std::endl;
+    FieldVector<double, 1> xd;
+    std::cout << className(xd) << std::endl;
+    FieldVector<complex<double>, 10> xcd;
+    std::cout << className(xcd) << std::endl;
+    std::cout << std::endl;
+
+    std::cout << "Adding const:" << std::endl;
+    const FieldVector<int, 3> cxi;
+    std::cout << className(cxi) << std::endl;
+    std::cout << std::endl;
+
+    std::cout << "If a variable is a reference can not be extracted (needs decltype as used below): " << std::endl;
+    FieldVector<double, 1> &rxd = xd;
+    std::cout << className(rxd) << std::endl;
+    std::cout << std::endl;
+
+    std::cout << "Extracting the class name using a type directly - "
+              << "also extractes references correctly: " << std::endl;
+    std::cout << Dune::className<decltype(rxd)>() << std::endl;
+    const FieldVector<double, 1> &rcxd = xd;
+    std::cout << Dune::className<decltype(rcxd)>() << std::endl;
+    const FieldVector<int, 3> &rcxi = cxi;
+    std::cout << Dune::className<decltype(rcxi)>() << std::endl;
+    std::cout << std::endl;
+
+    std::cout << "Test some further types:" << std::endl;
+    std::cout << Dune::className< volatile FieldVector<complex<double>, 10>& >() << std::endl;
+    std::cout << Dune::className< FieldVector<complex<double>, 10>&& >() << std::endl;
+    std::cout << std::endl;
+
+  } catch (Dune::Exception& e) {
+    std::cerr << e << std::endl;
+    return 1;
+  } catch (...) {
+    std::cerr << "Generic exception!" << std::endl;
+    return 2;
+  }
+}
-- 
GitLab