// lesson 6: functions // // ::define, ::sequence<...>> defines a function // a function sees nothing but its parameters. it gives back a type with // ::return, or ::void if it never does. calling it is a type too: // ::invoke_result_t>, 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() 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;