changeset 3:58777a883f54

Vastly improve replace_type
author Lewin Bormann <lbo@spheniscida.de>
date Wed, 25 Mar 2020 10:10:30 +0100
parents 20c6c0bec02a
children 90fe4346fcbc
files CMakeLists.txt src/replace_type.cc
diffstat 2 files changed, 59 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Tue Mar 24 19:50:07 2020 +0100
+++ b/CMakeLists.txt	Wed Mar 25 10:10:30 2020 +0100
@@ -7,3 +7,5 @@
 add_executable(binary src/binary.cc)
 
 add_executable(replace_type src/replace_type.cc)
+
+add_executable(fac src/fac.cc)
--- a/src/replace_type.cc	Tue Mar 24 19:50:07 2020 +0100
+++ b/src/replace_type.cc	Wed Mar 25 10:10:30 2020 +0100
@@ -1,40 +1,77 @@
 #include <iostream>
-
-class C {};
+#include <type_traits>
 
 template<typename C, typename X, typename Y>
 struct replace_type {
     typedef C type;
 };
 
+// Simple replacement.
 template<typename X, typename Y>
-struct replace_type<X*, X, Y> {
-    typedef Y* type;
-};
-
-template<typename X, typename Y>
-struct replace_type<X&, X, Y> {
-    typedef Y& type;
+struct replace_type<X, X, Y> {
+    typedef Y type;
 };
 
-template<typename R, typename X, typename Y>
-struct replace_type<R (*)(X), X, Y> {
-    typedef R (*type)(Y);
+namespace {
+    // For pointer/reference types, if C* == X, replace, otherwise continue replacing.
+    template<bool is_same, typename C, typename X, typename Y>
+    struct replace_type_ptr_helper {
+        typedef Y type;
+    };
+    template<typename C, typename X, typename Y>
+    struct replace_type_ptr_helper<true, C*, X, Y> {
+        typedef Y type;
+    };
+    template<typename C, typename X, typename Y>
+    struct replace_type_ptr_helper<false, C*, X, Y> {
+        typedef typename replace_type<C, X, Y>::type* type;
+    };
+    template<typename C, typename X, typename Y>
+    struct replace_type_ptr_helper<true, C&, X, Y> {
+        typedef Y type;
+    };
+    template<typename C, typename X, typename Y>
+    struct replace_type_ptr_helper<false, C&, X, Y> {
+        typedef typename replace_type<C, X, Y>::type& type;
+    };
+    template<typename C, typename X, typename Y>
+    struct replace_type_ptr_helper<true, C&&, X, Y> {
+        typedef Y type;
+    };
+    template<typename C, typename X, typename Y>
+    struct replace_type_ptr_helper<false, C&&, X, Y> {
+        typedef typename replace_type<C, X, Y>::type&& type;
+    };
+}
+
+template<typename C, typename X, typename Y>
+struct replace_type<C*, X, Y> {
+    typedef typename replace_type_ptr_helper<std::is_same<C*, X>::value, C*, X, Y>::type type;
 };
 
-template<typename X, typename Y>
-struct replace_type<X (*)(X), X, Y> {
-    typedef Y (*type)(Y);
+template<typename C, typename X, typename Y>
+struct replace_type<C&, X, Y> {
+    typedef typename replace_type_ptr_helper<std::is_same<C&, X>::value, C&, X, Y>::type type;
 };
 
-template<typename A, typename X, typename Y>
-struct replace_type<X (*)(A), X, Y> {
-    typedef Y (*type)(A);
+template<typename C, typename X, typename Y>
+struct replace_type<C&&, X, Y> {
+    typedef typename replace_type_ptr_helper<std::is_same<C&&, X>::value, C&&, X, Y>::type type;
+};
+
+template<typename C, typename X, typename Y>
+struct replace_type<const C, X, Y> {
+    typedef const typename replace_type_ptr_helper<std::is_same<const C, X>::value, const C, X, Y>::type type;
+};
+
+template<typename R, typename A, typename X, typename Y>
+struct replace_type<R (*)(A), X, Y> {
+    typedef typename replace_type<R, X, Y>::type (*type)(typename replace_type<A, X, Y>::type);
 };
 
 int main(void) {
-    typedef char& (*typ)(char& a);
+    typedef const long long* typ;
     std::cout << typeid(typ).name() << std::endl;
-    std::cout << typeid(replace_type<typ, unsigned, unsigned>::type).name() << std::endl;
+    std::cout << typeid(replace_type<typ, long long, unsigned>::type).name() << std::endl;
     return 0;
 }