hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/tutorial/06_functions.sfinae
blob: a85e5fa35f8a56320e5dcd29ebcd716db72ecc26 (plain)
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
// lesson 6: functions
//
// ::define<NAME, ::parameters<NAME, ...>, ::sequence<...>> defines a function
// a function sees nothing but its parameters. it gives back a type with
// ::return<TYPE>, or ::void if it never does. calling it is a type too:
// ::invoke_result_t<NAME, ::arguments<TYPE, ...>>, and every argument must be
// a ::decltype so it carries a value

::define<
    ::name<'s', 'q', 'u', 'a', 'r', 'e'>,
    ::parameters<::name<'x'>>,
    ::sequence<
        ::return<
            ::decltype(
                ::product<
                    ::value_of<::name<'x'>>,
                    ::value_of<::name<'x'>>
                >
            )
        >::commit
    >
>::commit;

// prints 25

::emit<
    ::invoke_result_t<
        ::name<'s', 'q', 'u', 'a', 'r', 'e'>,
        ::arguments<::decltype(::difference<'F', 'A'>)>
    >
>::commit;

// a function can return anything a type can be, which includes a tuple of
// characters, which is the closest thing to a string you will get

::define<
    ::name<'g', 'r', 'e', 'e', 't'>,
    ::parameters<>,
    ::sequence<
        ::return<
            ::tuple<
        ::integral_constant<::char, ::difference<'h', '\0'>>,
        ::integral_constant<::char, ::difference<'e', '\0'>>,
        ::integral_constant<::char, ::difference<'y', '\0'>>
            >
        >::commit
    >
>::commit;

::emit<
    ::invoke_result_t<
        ::name<'g', 'r', 'e', 'e', 't'>,
        ::arguments<>
    >
>::commit;

// the result is a type. to use it as a value in arithmetic, ::declval<T>() gets
// the value back out. the parentheses are mandatory. it is a function, after all
// this prints 10

::emit<
    ::decltype(
        ::sum<
            ::declval<
                ::invoke_result_t<
                    ::name<'s', 'q', 'u', 'a', 'r', 'e'>,
                    ::arguments<::decltype(::difference<'D', 'A'>)>
                >
            >(),
            ::difference<'B', 'A'>
        >
    )
>::commit;

// recursion works, because nothing stopped it. factorial of 5

::define<
    ::name<'f', 'a', 'c', 't'>,
    ::parameters<::name<'n'>>,
    ::sequence<
        ::enable_if_t<
            ::less<
                ::value_of<::name<'n'>>,
                ::difference<'B', 'A'>
            >::value,
            ::sequence<
                ::return<::decltype(::difference<'B', 'A'>)>::commit
            >
        >::commit,
        ::return<
            ::decltype(
                ::product<
                    ::value_of<::name<'n'>>,
                    ::declval<
                        ::invoke_result_t<
                            ::name<'f', 'a', 'c', 't'>,
                            ::arguments<
                                ::decltype(
                                    ::sum<
                                        ::value_of<::name<'n'>>,
                                        ::difference<'A', 'B'>
                                    >
                                )
                            >
                        >
                    >()
                >
            )
        >::commit
    >
>::commit;

::emit<
    ::invoke_result_t<
        ::name<'f', 'a', 'c', 't'>,
        ::arguments<::decltype(::difference<'F', 'A'>)>
    >
>::commit;