A solution to exercise 2.1 of "C++ Template Metaprogramming"

hi,
I have benefited from the kind help of so many programmers in this site that I felt I needed to give something back. As it happened, a problem I had no idea how to solve has finally seen some light and I believe I found a way to solve it. I want to share it with the community and see if others have other ideas or suggestions. Will be happy to hear from all of you!!

The problem was taken from Exercise 2.1 of "C++ Template Metaprogramming" by Abrahams and Gurtovoy and is stated like this:

Write a ternary metafunction replace_type<c,x,y> that takes an arbitrary compound type c as its first parameter and replaces all occurrences of a type x within c with y.

The idea for this metafunction is we can replace types in c like so:


1
2
3
4
5
cout << "bool* const ==> int* const: " << is_same<typename replace_type<bool*const, bool, int>::type, int* const>::value << endl;
            
cout << "bool* [30] ==> int* [30]: " << is_same<typename replace_type<bool*[30], bool, int>::type, int* [30]>::value << endl;
            
cout << "char *& ==> int&: " << is_same<typename replace_type<char *&, char*, int>::type, int&>::value << ends;


I am not concerned as to how useful this might be, because to me its value resides in being a very good exercise in entering the world of metaprogramming.

My solution came as a set of partial template specializations as seen below.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
template<typename c, typename x, typename y>
        struct replace_type;
        
        // C == X
        template <typename c, typename y>
        struct replace_type<c,c,y>
        {
            using type = y;
        };
        
        // C == X + const
        template <typename c, typename y>
        struct replace_type<c const,c,y>
        {
            using type = typename boost::add_const<y>::type;
        };
        
        // C == X + pointer
        template <typename c, typename y>
        struct replace_type<c*,c,y>
        {
            using type = typename boost::add_pointer<y>::type;
        };

        // C == X + pointer + pointer
        template <typename c, typename y>
        struct replace_type<c**,c,y>
        {
            using type = typename boost::add_pointer<typename replace_type<c*,c,y>::type>::type; 
        };

        // C == X + pointer + pointer + const
        template <typename c, typename y>
        struct replace_type<c**const,c,y>
        {
            using type = typename boost::add_const<typename replace_type<c**,c,y>::type>::type; 
        };

        // C = X + pointer + const
        template <typename c, typename y>
        struct replace_type<c* const,c,y>
        {
            using type = typename boost::add_const<typename replace_type<c*,c,y>::type>::type; 
        };

        // C = X + const + pointer
        template <typename c, typename y>
        struct replace_type<c const*,c,y>
        {
            using type = typename boost::add_pointer<typename replace_type<c const,c,y>::type>::type; 
        };

        
        template<typename Element, size_t N>
        struct add_dim
        {
            using type = Element[N];
        };
        
        // C == X + [N]
        template <typename c, size_t N, typename y>
        struct replace_type<c[N],c,y>
        {
            using type = typename add_dim<y, N>::type;
        };
        
        // C == X + pointer + [N]
        template <typename c, size_t N, typename y>
        struct replace_type<c*[N],c,y>
        {
            using type = typename add_dim< typename replace_type<c*,c,y>::type, N>::type;
        };
        
        // C == X + pointer + pointer + [N]
        template <typename c, size_t N, typename y>
        struct replace_type<c**[N],c,y>
        {
            using type = typename add_dim< typename replace_type<c**,c,y>::type, N>::type;
        };

        // C == X + reference
        template <typename c, typename y>
        struct replace_type<c&,c,y>
        {
            using type = typename boost::add_reference<y>::type;
        };

        // C == X + rvalue reference
        template <typename c, typename y>
        struct replace_type<c&&,c,y>
        {
            using type = typename boost::add_rvalue_reference<y>::type;
        };

        // C == X + reference + const
        template <typename c, typename y>
        struct replace_type<c const &,c,y>
        {
            using type = typename boost::add_const<typename replace_type<c&,c,y>::type>::type;
        };
        
        // C == X + reference + pointer
        template <typename c, typename y>
        struct replace_type<c*&,c,y>
        {
            using type = typename boost::add_reference<typename boost::add_pointer<y>::type>::type;
        };
        

        // C == X F ()
        template <typename c, typename y>
        struct replace_type<c(),c,y>
        {
            using type = y(*)();
        };
        
        // C == X& F (X&)
        template <typename c, typename y>
        struct replace_type<c&(c&),c,y>
        {
            using type = y&(*)(y&);
        };


Examples of its use include:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
        int func()
        {
            return 1;
        }

        bool is_it()
        {
            return true;
        }
        
        int another()
        {
            return 1;
        }
        bool& aBool(bool& a) {
            return a;
        }
        int& an(int& y)
        {
            return y;
        }
        int main()
        {
            using namespace std;
            
            replace_type<decltype(is_it), bool, int>::type f = another;
            cout << f() << endl;
            
            replace_type<decltype(aBool), bool, int>::type g = an;
            int v = 45;
            cout << g(v) << endl;
            
            using CC = bool * const;
            using CC_replace = replace_type<CC, bool, int>;
            
            
            using new_type = CC_replace::type;
            
            new_type t = nullptr;
            
            replace_type<bool**const, bool, int>::type x = nullptr;
            
            replace_type<bool&&, bool, int>::type y  = func();
            int&& yy = func();
            
            int m = 4;
            int* pm = &m;
            replace_type<bool const&, bool const, int>::type dd = m;
            
            int*& pp = pm;
            
            cout << traits<bool*&>::is_reference;
            cout << traits<bool*&>::is_pointer;
            cout << endl;
            
            replace_type<bool*&, bool, int>::type p = pm;
        }



Any thoughts?

Regards,
Juan Dent
Last edited on
Topic archived. No new replies allowed.